"use client";

import { ExternalLink as ExternalLinkIcon, Trash2 } from "lucide-react";
import { useState, useTransition } from "react";
import {
  checkIntegrationAction,
  deleteIntegrationAction,
  saveIntegrationKeyAction,
} from "@/app/(app)/settings/integrations/actions";
import { Spinner } from "@/components/app/spinner";
import { StatusBadge } from "@/components/app/status-badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  INTEGRATION_STATUS_LABELS,
  INTEGRATION_STATUS_TONES,
  KEY_MAX,
  KEY_MIN,
  provider as providerDefinition,
  type Integration,
} from "@/lib/integrations";

// Saisie de la clé BYOK d'un fournisseur (spec Imports §1.11), au pattern des formulaires de
// réglages : état local, Server Action, Problem Details relayé tel quel.
//
// **Le champ est en écriture seule.** Il n'est jamais pré-rempli, même après enregistrement :
// l'api ne rend pas la clé, et un champ qui la réafficherait la remettrait dans le DOM, dans
// le cache du navigateur et dans les gestionnaires de mot de passe pour rien. Ce qu'on montre
// à la place, c'est l'empreinte `••••••cd12` — assez pour reconnaître *laquelle* de ses clés
// est branchée, trop peu pour la rejouer.

export function IntegrationKeyForm({
  provider,
  integration,
}: {
  provider: "mangools";
  integration: Integration | null;
}) {
  const [current, setCurrent] = useState(integration);
  const [key, setKey] = useState("");
  const [error, setError] = useState<string | null>(null);
  const [notice, setNotice] = useState<string | null>(null);
  const [pending, startTransition] = useTransition();
  const [confirming, setConfirming] = useState(false);

  const run = (work: () => Promise<void>) => {
    setError(null);
    setNotice(null);
    startTransition(work);
  };

  return (
    <div className="space-y-4">
      {/*  Le statut et son action vont ensemble : « Vérifier la clé » n'a de sens qu'à côté de
           l'état qu'elle change, pas en bas de carte. La rangée wrappe à 375 px. */}
      <div className="flex flex-wrap items-center gap-x-3 gap-y-2 text-sm">
        {current ? (
          <>
            <StatusBadge tone={INTEGRATION_STATUS_TONES[current.status] ?? "neutral"}>
              {INTEGRATION_STATUS_LABELS[current.status] ?? current.status}
            </StatusBadge>
            <code className="text-foreground-faint min-w-0 font-mono break-all">
              {current.credentials_hint}
            </code>
            <Button
              type="button"
              variant="outline"
              size="sm"
              disabled={pending}
              onClick={() =>
                run(async () => {
                  const result = await checkIntegrationAction(current.id);
                  if ("error" in result) {
                    setError(result.error);
                    return;
                  }
                  setCurrent(result.integration);
                  setNotice(
                    result.integration.status === "connected"
                      ? "Le fournisseur a accepté la clé."
                      : "Le fournisseur a refusé la clé.",
                  );
                })
              }
            >
              {pending ? <Spinner size="sm" data-icon="inline-start" /> : null}
              Vérifier la clé
            </Button>
          </>
        ) : (
          <StatusBadge tone="neutral">Non configurée</StatusBadge>
        )}
      </div>

      {current?.status_error ? (
        <p role="alert" className="text-destructive text-sm">
          {current.status_error}
        </p>
      ) : null}

      <form
        className="flex max-w-lg flex-wrap items-end gap-2"
        onSubmit={(event) => {
          event.preventDefault();
          run(async () => {
            const result = await saveIntegrationKeyAction({
              id: current?.id ?? null,
              provider,
              api_key: key,
            });
            if ("error" in result) {
              setError(result.error);
              return;
            }
            setCurrent(result.integration);
            // Le champ est vidé aussitôt : la clé ne doit pas rester dans le DOM.
            setKey("");
            setNotice("Clé enregistrée. Vérifiez-la pour confirmer qu'elle fonctionne.");
          });
        }}
      >
        <div className="min-w-0 flex-1 space-y-1">
          <Label htmlFor={`${provider}-key`}>{current ? "Remplacer la clé" : "Clé d'API"}</Label>
          <Input
            id={`${provider}-key`}
            type="password"
            autoComplete="off"
            spellCheck={false}
            minLength={KEY_MIN}
            maxLength={KEY_MAX}
            placeholder="Collez votre clé"
            value={key}
            onChange={(event) => {
              setKey(event.target.value);
              setNotice(null);
            }}
          />
        </div>
        <Button type="submit" disabled={pending || key.trim().length < KEY_MIN}>
          {pending ? <Spinner size="sm" data-icon="inline-start" /> : null}
          Enregistrer
        </Button>
      </form>

      <ProviderKeyHelp provider={provider} />

      {/*  « Supprimer la clé » est rendu en `destructive` : le geste est irréversible côté
           fournisseur, il ne doit pas se rendre comme un lien anodin à côté d'« Enregistrer ». */}
      {current ? (
        <div className="flex flex-wrap gap-2">
          {confirming ? (
            <>
              <Button
                type="button"
                variant="destructive"
                size="sm"
                disabled={pending}
                onClick={() =>
                  run(async () => {
                    const result = await deleteIntegrationAction(current.id);
                    if ("error" in result) {
                      setError(result.error);
                      return;
                    }
                    setCurrent(null);
                    setConfirming(false);
                    setNotice("Clé supprimée. Vos mots-clés déjà importés restent en place.");
                  })
                }
              >
                Confirmer la suppression
              </Button>
              <Button
                type="button"
                variant="ghost"
                size="sm"
                onClick={() => setConfirming(false)}
                disabled={pending}
              >
                Annuler
              </Button>
            </>
          ) : (
            <Button
              type="button"
              variant="destructive"
              size="sm"
              disabled={pending}
              onClick={() => setConfirming(true)}
            >
              <Trash2 data-icon="inline-start" />
              Supprimer la clé
            </Button>
          )}
        </div>
      ) : null}

      {confirming ? (
        <p className="text-muted-foreground text-sm">
          Vos mots-clés déjà importés restent dans le réservoir.
        </p>
      ) : null}

      {error ? (
        <p role="alert" className="text-destructive text-sm">
          {error}
        </p>
      ) : notice ? (
        <p className="text-muted-foreground text-sm">{notice}</p>
      ) : null}
    </div>
  );
}

/**
 * Où trouver sa clé chez ce fournisseur : **deux liens, aucune phrase**.
 *
 * Sans eux, l'écran est un cul-de-sac pour qui n'a pas encore de clé — la fonctionnalité
 * paraît cassée alors qu'il ne manque qu'une adresse. Mais la phrase qui les enrobait
 * (« crée un compte gratuit… ») posait deux problèmes : elle tutoyait dans un écran qui
 * vouvoie partout ailleurs (« Collez votre clé »), et elle affirmait « gratuit » — ce que
 * personne n'a vérifié, l'API Mangools paraissant réservée aux plans payants. Deux libellés
 * d'action disent la même chose sans rien promettre.
 *
 * Les adresses viennent de la **définition du fournisseur** (`PROVIDERS`), jamais du JSX : le
 * prochain fournisseur hérite du bloc en déclarant ses URL, sans qu'on retouche cet écran.
 */
function ProviderKeyHelp({ provider }: { provider: string }) {
  const definition = providerDefinition(provider);
  if (definition === null) return null;
  return (
    <div className="flex min-w-0 flex-wrap items-center gap-x-4 gap-y-1 text-sm">
      <ExternalLink href={definition.signupUrl}>Créer un compte</ExternalLink>
      <ExternalLink href={definition.tokenUrl}>Obtenir une clé</ExternalLink>
    </div>
  );
}

/** Un lien externe. `noreferrer noopener` sur tout ce qui sort d'ici. */
function ExternalLink({ href, children }: { href: string; children: React.ReactNode }) {
  return (
    <a
      href={href}
      target="_blank"
      rel="noreferrer noopener"
      //  `--brand-text` : la marque en texte, le token prévu pour ça. Le soulignement reste —
      //  la couleur seule ne signale pas un lien à qui ne la distingue pas.
      className="text-brand-text inline-flex items-center gap-1 underline underline-offset-2"
    >
      {children}
      <ExternalLinkIcon data-icon="inline-end" className="size-3.5" />
    </a>
  );
}
