"use client";

/**
 * ── APPRENTISSAGE ────────────────────────────────────────────────────────────
 * LE PONT ENTRE LE STATIQUE ET LE PHP
 *
 * Le site n'a pas de serveur : aucune page ne peut « traiter » un POST. Ce
 * formulaire envoie donc ses données en `fetch()` vers un script PHP autonome
 * (`api-contact.php`) déposé à la racine de www/, à côté du site exporté.
 * Ce PHP, lui, est bien exécuté par Apache — c'est le terrain que tu connais.
 *
 * Le composant est donc « client » : il a un état (les champs, l'envoi en
 * cours, le message de retour) et il écoute des événements.
 *
 * Format d'envoi : `URLSearchParams`, c'est-à-dire le bon vieux
 * `application/x-www-form-urlencoded`. Deux avantages : côté PHP on retrouve
 * simplement `$_POST['nom']`, et le navigateur n'envoie pas de requête
 * préparatoire OPTIONS (« preflight ») comme il le ferait avec du JSON.
 * ─────────────────────────────────────────────────────────────────────────────
 */

import { useEffect, useRef, useState } from "react";
import { IconeCoche } from "@/components/Icones";
import { CAPTCHA_NON_CONFIGURE, CLE_SITE_HCAPTCHA } from "@/lib/captcha";
import { SITE } from "@/lib/site";

/* Déclaration TypeScript de ce que le script hCaptcha ajoute à `window`.
   Sans ça, le compilateur refuse `window.hcaptcha` — il ne connaît pas. */
declare global {
  interface Window {
    hcaptcha?: {
      render: (
        element: HTMLElement,
        options: Record<string, unknown>,
      ) => string;
      reset: (widgetId?: string) => void;
    };
    adtRendreCaptcha?: () => void;
  }
}

type Champs = { nom: string; tel: string; email: string; message: string };
type Etat = "repos" | "envoi" | "succes" | "erreur";

const CHAMPS_VIDES: Champs = { nom: "", tel: "", email: "", message: "" };

/** Validation côté navigateur. Elle sert le confort, pas la sécurité :
 *  la vraie validation, la seule qui compte, est refaite dans le PHP. */
function valider(champs: Champs): Partial<Record<keyof Champs, string>> {
  const erreurs: Partial<Record<keyof Champs, string>> = {};

  if (champs.nom.trim().length < 2) {
    erreurs.nom = "Indiquez au moins votre nom.";
  }
  if (!/^[0-9+().\s-]{6,20}$/.test(champs.tel.trim())) {
    erreurs.tel = "Numéro de téléphone incomplet.";
  }
  if (!/^[^\s@]+@[^\s@]+\.[a-z]{2,}$/i.test(champs.email.trim())) {
    erreurs.email = "Adresse e-mail invalide.";
  }
  if (champs.message.trim().length < 10) {
    erreurs.message = "Dites-nous en deux lignes ce que vous cherchez.";
  }

  return erreurs;
}

export function FormulaireContact() {
  const [champs, setChamps] = useState<Champs>(CHAMPS_VIDES);
  const [erreurs, setErreurs] = useState<Partial<Record<keyof Champs, string>>>({});
  const [etat, setEtat] = useState<Etat>("repos");
  const [messageRetour, setMessageRetour] = useState("");
  const [jetonCaptcha, setJetonCaptcha] = useState("");

  // `useRef` = une case mémoire qui survit aux re-rendus SANS en déclencher.
  // Parfait pour retenir l'identifiant du widget hCaptcha.
  const conteneurCaptcha = useRef<HTMLDivElement>(null);
  const idWidget = useRef<string | null>(null);

  /* ── Chargement et affichage du widget hCaptcha ────────────────────────── */
  useEffect(() => {
    if (CAPTCHA_NON_CONFIGURE) return;

    const rendre = () => {
      // Le garde-fou `idWidget.current !== null` est indispensable : en
      // développement, React exécute les effets deux fois pour débusquer les
      // bugs, et sans lui on afficherait deux captchas.
      if (!conteneurCaptcha.current || idWidget.current !== null) return;
      if (!window.hcaptcha) return;

      idWidget.current = window.hcaptcha.render(conteneurCaptcha.current, {
        sitekey: CLE_SITE_HCAPTCHA,
        hl: "fr",
        callback: (jeton: string) => setJetonCaptcha(jeton),
        "expired-callback": () => setJetonCaptcha(""),
        "error-callback": () => setJetonCaptcha(""),
      });
    };

    if (window.hcaptcha) {
      rendre();
      return;
    }

    // Le script n'est chargé que sur cette page, et seulement une fois.
    window.adtRendreCaptcha = rendre;
    if (!document.getElementById("script-hcaptcha")) {
      const script = document.createElement("script");
      script.id = "script-hcaptcha";
      script.src =
        "https://js.hcaptcha.com/1/api.js?render=explicit&onload=adtRendreCaptcha";
      script.async = true;
      script.defer = true;
      document.head.appendChild(script);
    }
  }, []);

  const majChamp = (nom: keyof Champs) => (
    evenement: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
  ) => {
    setChamps((precedent) => ({ ...precedent, [nom]: evenement.target.value }));
  };

  /* ── Envoi ─────────────────────────────────────────────────────────────── */
  async function envoyer(evenement: React.FormEvent<HTMLFormElement>) {
    // Sans ça, le navigateur rechargerait la page comme un formulaire HTML
    // classique — et il n'y a personne pour répondre à ce POST.
    evenement.preventDefault();

    const nouvellesErreurs = valider(champs);
    setErreurs(nouvellesErreurs);
    if (Object.keys(nouvellesErreurs).length > 0) return;

    if (CAPTCHA_NON_CONFIGURE) {
      setEtat("erreur");
      setMessageRetour(
        "La vérification anti-robot n'est pas encore configurée sur ce site. " +
          "Écrivez-nous directement par e-mail en attendant.",
      );
      return;
    }

    if (!jetonCaptcha) {
      setEtat("erreur");
      setMessageRetour("Merci de cocher la case de vérification anti-robot.");
      return;
    }

    setEtat("envoi");
    setMessageRetour("");

    try {
      const formulaire = evenement.currentTarget;
      const corps = new URLSearchParams({
        name: champs.nom.trim(),
        tel: champs.tel.trim(),
        email: champs.email.trim(),
        message: champs.message.trim(),
        // Piège à robots : champ invisible qu'un humain ne remplit jamais.
        site_web: (formulaire.elements.namedItem("site_web") as HTMLInputElement)
          .value,
        "h-captcha-response": jetonCaptcha,
      });

      const reponse = await fetch(SITE.endpointContact, {
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: corps.toString(),
      });

      const donnees: { success?: boolean; message?: string } = await reponse
        .json()
        .catch(() => ({}));

      if (reponse.ok && donnees.success) {
        setEtat("succes");
        setMessageRetour(
          donnees.message ?? "Message envoyé. On vous répond rapidement.",
        );
        setChamps(CHAMPS_VIDES);
      } else {
        setEtat("erreur");
        setMessageRetour(
          donnees.message ??
            "L'envoi a échoué. Réessayez, ou écrivez-nous directement par e-mail.",
        );
      }
    } catch {
      setEtat("erreur");
      setMessageRetour(
        "Impossible de joindre le serveur. Vérifiez votre connexion, ou " +
          "écrivez-nous directement par e-mail.",
      );
    } finally {
      // Dans tous les cas on redonne un captcha neuf : un jeton hCaptcha
      // n'est valable qu'une fois.
      if (window.hcaptcha && idWidget.current !== null) {
        window.hcaptcha.reset(idWidget.current);
      }
      setJetonCaptcha("");
    }
  }

  /* ── Écran de confirmation ─────────────────────────────────────────────── */
  if (etat === "succes") {
    return (
      <div
        className="rounded-sm border-2 border-saumon bg-saumon-clair p-8"
        role="status"
      >
        <IconeCoche className="h-10 w-10 text-saumon-texte" />
        <h2 className="mt-4 text-2xl">Message parti.</h2>
        <p className="mt-3 text-[1.0625rem] leading-relaxed text-gris">
          {messageRetour}
        </p>
        <button
          type="button"
          onClick={() => {
            setEtat("repos");
            setMessageRetour("");
          }}
          className="bouton-secondaire mt-7"
        >
          Écrire un autre message
        </button>
      </div>
    );
  }

  const classeChamp =
    "w-full rounded-sm border border-trait bg-white px-4 py-3 text-[1rem] " +
    "text-anthracite outline-none transition-colors placeholder:text-gris/50 " +
    "focus:border-saumon";

  return (
    <form onSubmit={envoyer} noValidate className="space-y-5">
      {/* ── Nom ── */}
      <div>
        <label htmlFor="nom" className="mb-2 block text-sm font-bold">
          Votre nom <span className="text-saumon-texte">*</span>
        </label>
        <input
          id="nom"
          name="name"
          type="text"
          autoComplete="name"
          value={champs.nom}
          onChange={majChamp("nom")}
          aria-invalid={Boolean(erreurs.nom)}
          aria-describedby={erreurs.nom ? "erreur-nom" : undefined}
          className={classeChamp}
          placeholder="Prénom et nom"
        />
        {erreurs.nom && (
          <p id="erreur-nom" className="mt-2 text-sm font-semibold text-[#B3261E]">
            {erreurs.nom}
          </p>
        )}
      </div>

      {/* ── Téléphone + e-mail ── */}
      <div className="grid gap-5 sm:grid-cols-2">
        <div>
          <label htmlFor="tel" className="mb-2 block text-sm font-bold">
            Téléphone <span className="text-saumon-texte">*</span>
          </label>
          <input
            id="tel"
            name="tel"
            type="tel"
            autoComplete="tel"
            value={champs.tel}
            onChange={majChamp("tel")}
            aria-invalid={Boolean(erreurs.tel)}
            aria-describedby={erreurs.tel ? "erreur-tel" : undefined}
            className={classeChamp}
            placeholder="06 00 00 00 00"
          />
          {erreurs.tel && (
            <p id="erreur-tel" className="mt-2 text-sm font-semibold text-[#B3261E]">
              {erreurs.tel}
            </p>
          )}
        </div>

        <div>
          <label htmlFor="email" className="mb-2 block text-sm font-bold">
            E-mail <span className="text-saumon-texte">*</span>
          </label>
          <input
            id="email"
            name="email"
            type="email"
            autoComplete="email"
            value={champs.email}
            onChange={majChamp("email")}
            aria-invalid={Boolean(erreurs.email)}
            aria-describedby={erreurs.email ? "erreur-email" : undefined}
            className={classeChamp}
            placeholder="vous@exemple.fr"
          />
          {erreurs.email && (
            <p
              id="erreur-email"
              className="mt-2 text-sm font-semibold text-[#B3261E]"
            >
              {erreurs.email}
            </p>
          )}
        </div>
      </div>

      {/* ── Message ── */}
      <div>
        <label htmlFor="message" className="mb-2 block text-sm font-bold">
          Votre besoin <span className="text-saumon-texte">*</span>
        </label>
        <textarea
          id="message"
          name="message"
          rows={6}
          value={champs.message}
          onChange={majChamp("message")}
          aria-invalid={Boolean(erreurs.message)}
          aria-describedby={erreurs.message ? "erreur-message" : undefined}
          className={classeChamp}
          placeholder="Ce qui vous fait perdre du temps aujourd'hui, ce que vous aimeriez ne plus faire à la main…"
        />
        {erreurs.message && (
          <p
            id="erreur-message"
            className="mt-2 text-sm font-semibold text-[#B3261E]"
          >
            {erreurs.message}
          </p>
        )}
      </div>

      {/* ── Honeypot ──
          Invisible à l'écran ET pour les lecteurs d'écran (aria-hidden),
          mais bien présent dans le HTML. Les robots remplissent tous les
          champs qu'ils trouvent : s'il est rempli, le PHP jette la demande.
          `sr-only` ne suffirait pas — un lecteur d'écran le lirait. */}
      <div
        aria-hidden="true"
        className="pointer-events-none absolute -left-[9999px] h-0 w-0 overflow-hidden"
      >
        <label htmlFor="site_web">Ne pas remplir ce champ</label>
        <input id="site_web" name="site_web" type="text" tabIndex={-1} autoComplete="off" />
      </div>

      {/* ── Captcha ── */}
      <div>
        {CAPTCHA_NON_CONFIGURE ? (
          <p className="rounded-sm border border-[#E0C97A] bg-[#FFF8E1] p-4 text-sm leading-relaxed">
            <span className="a-completer">[À COMPLÉTER]</span> clé de site
            hCaptcha absente : la protection anti-robot n&apos;est pas active et
            l&apos;envoi est bloqué. Renseigner{" "}
            <code className="font-mono text-[0.85em]">
              NEXT_PUBLIC_HCAPTCHA_SITEKEY
            </code>{" "}
            puis relancer le build.
          </p>
        ) : (
          <div ref={conteneurCaptcha} />
        )}
      </div>

      {/* ── Bouton + retour ── */}
      <div className="flex flex-col gap-4 pt-1 sm:flex-row sm:items-center">
        <button
          type="submit"
          disabled={etat === "envoi"}
          className="bouton-primaire disabled:cursor-not-allowed disabled:opacity-60"
        >
          {etat === "envoi" ? "Envoi en cours…" : "Envoyer le message"}
        </button>

        <p className="text-sm text-gris">
          Réponse sous 48 h ouvrées.
        </p>
      </div>

      {/* `aria-live` : le lecteur d'écran annonce ce message dès qu'il change,
          sans que l'utilisateur ait à aller le chercher. */}
      <p
        aria-live="polite"
        className={
          etat === "erreur"
            ? "rounded-sm border border-[#B3261E]/30 bg-[#FDECEA] p-4 text-sm font-semibold text-[#8C1D18]"
            : "sr-only"
        }
      >
        {etat === "erreur" ? messageRetour : ""}
      </p>

      <p className="text-xs leading-relaxed text-gris">
        Les informations transmises servent uniquement à vous répondre. Elles ne
        sont ni revendues ni utilisées pour de la prospection. Voir les{" "}
        <a
          href="/mentions-legales/"
          className="font-semibold underline underline-offset-2"
        >
          mentions légales
        </a>
        .
      </p>
    </form>
  );
}
