import { useEffect, useMemo, useState } from "react";
import * as DialogPrimitive from "@radix-ui/react-dialog";
import {
  Check,
  AlertCircle,
  ArrowRight,
  FileText,
  Calendar,
  X,
} from "lucide-react";
import { toast } from "sonner";

import {
  usePendingCheckins,
  useCheckinPaid,
  useCheckinStillPending,
  type PendingCheckinInvoice,
} from "@/lib/checkin";
import { formatDate, formatDueDelta, formatEuros, isOverdue } from "@/lib/format";
import { cn } from "@/lib/utils";

import { Button } from "@/components/ui/Button";

/**
 * Modale qui se déclenche quand l'org a des factures en
 * `awaiting_user_confirmation`. Pour chacune, l'user répond directement :
 *   - "Oui, payée"     → mark paid + cancel relances
 *   - "Non, impayée"   → schedule relances + status → in_relance
 *   - "Plus tard"      → skip session-only, on passe à la suivante
 *
 * UX :
 *   - Mobile : bottom-sheet qui slide up depuis le bas, full-width avec
 *              safe-area-inset-bottom, coins arrondis en haut, contenu
 *              scrollable. Plus de pouce-friendly.
 *   - Desktop : modale centrée classique, max 540px.
 *
 * Stratégie de queue : on s'appuie sur le serveur comme source de vérité.
 * Après chaque réponse, l'invoice quitte le statut `awaiting_user_confirmation`
 * et disparaît du refetch. On affiche **toujours queue[0]**, donc la
 * suivante remonte naturellement à la position 0 — pas de cursor à gérer.
 *
 * Stratégie de re-pop :
 *   - X (close)        → ferme pour MAINTENANT seulement
 *   - Refocus / visible → reset le dismiss → si pending non vide après
 *                         refetch automatique TanStack Query, la modale
 *                         re-pop pour rappeler à l'user de répondre.
 *   - "Plus tard" persist en mémoire le temps de la session — on ne
 *     re-spame pas la même facture toutes les 5 minutes.
 */
export function InAppCheckinModal() {
  const { data: pending = [], isLoading } = usePendingCheckins();
  const paidMutation = useCheckinPaid();
  const stillPendingMutation = useCheckinStillPending();

  const [skipped, setSkipped] = useState<Set<string>>(new Set());
  // dismissed = "fermé maintenant" (X). Pas persistant — au refocus de
  // la fenêtre, on reset à false pour redonner sa chance à la modale.
  const [dismissed, setDismissed] = useState(false);

  // Reset le dismiss au refocus de l'onglet ou au retour de visibilité.
  // TanStack Query refetch déjà sur focus (par défaut) → si pending
  // change pendant qu'on était sur un autre onglet, la modale reflète.
  useEffect(() => {
    const reset = () => setDismissed(false);
    const onVisibility = () => {
      if (document.visibilityState === "visible") reset();
    };
    window.addEventListener("focus", reset);
    document.addEventListener("visibilitychange", onVisibility);
    return () => {
      window.removeEventListener("focus", reset);
      document.removeEventListener("visibilitychange", onVisibility);
    };
  }, []);

  const queue = useMemo<PendingCheckinInvoice[]>(
    () => pending.filter((p) => !skipped.has(p.id)),
    [pending, skipped],
  );
  const current = queue[0];
  const totalSeen = pending.length;
  const positionLeft = queue.length;

  const shouldOpen = !isLoading && !dismissed && queue.length > 0;

  const handleClose = () => {
    setDismissed(true);
  };

  const onPaid = () => {
    if (!current) return;
    paidMutation.mutate(current.id, {
      onSuccess: () => {
        toast.success(`${current.numero} marquée encaissée. + 1 rubis.`);
      },
      onError: () =>
        toast.error("Impossible de marquer la facture. Réessayez."),
    });
  };

  const onStillPending = () => {
    if (!current) return;
    stillPendingMutation.mutate(current.id, {
      onSuccess: () => {
        toast.success(`Relances activées pour ${current.numero}.`);
      },
      onError: () =>
        toast.error("Impossible de programmer les relances. Réessayez."),
    });
  };

  const onSkip = () => {
    if (!current) return;
    setSkipped((prev) => {
      const next = new Set(prev);
      next.add(current.id);
      return next;
    });
  };

  if (!current) return null;

  const isPending =
    paidMutation.isPending || stillPendingMutation.isPending;
  const cursorLabel = `${totalSeen - positionLeft + 1} / ${totalSeen}`;
  const remaining = positionLeft - 1;

  return (
    <DialogPrimitive.Root
      open={shouldOpen}
      onOpenChange={(open) => {
        if (!open) handleClose();
      }}
    >
      <DialogPrimitive.Portal>
        <DialogPrimitive.Overlay
          className={cn(
            "fixed inset-0 z-50 bg-ink/35 backdrop-blur-[2px]",
            "data-[state=open]:animate-in data-[state=open]:fade-in-0",
            "data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
          )}
        />
        <DialogPrimitive.Content
          className={cn(
            "fixed z-50 bg-cream shadow-card overflow-y-auto",
            // — Mobile : bottom-sheet
            "bottom-0 inset-x-0 max-h-[92vh] rounded-t-[20px] border-t border-line",
            "px-5 pt-4 pb-[max(1.5rem,env(safe-area-inset-bottom))]",
            "data-[state=open]:animate-in data-[state=open]:slide-in-from-bottom",
            "data-[state=closed]:animate-out data-[state=closed]:slide-out-to-bottom",
            // — Desktop : modale centrée classique
            "sm:bottom-auto sm:inset-x-auto sm:left-1/2 sm:top-1/2 sm:-translate-x-1/2 sm:-translate-y-1/2",
            "sm:w-[calc(100vw-2rem)] sm:max-w-[520px] sm:max-h-[90vh]",
            "sm:rounded-card sm:border sm:border-line sm:p-7",
            "sm:data-[state=open]:slide-in-from-bottom-0 sm:data-[state=open]:zoom-in-95",
            "sm:data-[state=closed]:slide-out-to-bottom-0 sm:data-[state=closed]:zoom-out-95",
          )}
        >
          {/* Drag handle visuel — exclusivement mobile, signal "tu peux fermer". */}
          <div
            aria-hidden="true"
            className="sm:hidden mx-auto mb-4 h-1 w-10 rounded-full bg-ink/15"
          />

          {/* Header */}
          <div className="flex items-start justify-between gap-3">
            <div className="min-w-0 flex-1">
              <p className="text-[10.5px] uppercase tracking-[0.12em] text-rubis font-semibold">
                Confirmation · {cursorLabel}
              </p>
              <DialogPrimitive.Title
                className={cn(
                  "mt-1 font-display font-semibold tracking-[-0.018em] text-ink",
                  "text-[19px] leading-tight",
                )}
              >
                Avez-vous été{" "}
                <em className="text-rubis not-italic">payé</em> sur cette facture ?
              </DialogPrimitive.Title>
              <DialogPrimitive.Description className="mt-1.5 text-[13px] text-ink-3 leading-relaxed">
                Aucune relance ne part sans votre validation. Si la facture est
                réglée, on évite l'email inutile et on encaisse +1 rubis.
              </DialogPrimitive.Description>
            </div>
            <DialogPrimitive.Close
              className={cn(
                "shrink-0 inline-flex size-8 items-center justify-center cursor-pointer",
                "rounded-default text-ink-3 hover:bg-cream-2 hover:text-ink",
                "transition-colors focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-rubis-glow",
              )}
              aria-label="Fermer"
            >
              <X size={16} aria-hidden="true" />
            </DialogPrimitive.Close>
          </div>

          {/* Card facture */}
          <div className="mt-5">
            <InvoiceCard invoice={current} />
          </div>

          {/* Actions principales */}
          <div className="mt-5 flex flex-col gap-2.5">
            <Button
              size="md"
              variant="primary"
              loading={paidMutation.isPending}
              disabled={isPending}
              onClick={onPaid}
              className="w-full justify-start"
            >
              <Check size={15} aria-hidden="true" />
              Oui — la facture est payée
            </Button>
            <Button
              size="md"
              variant="secondary"
              loading={stillPendingMutation.isPending}
              disabled={isPending}
              onClick={onStillPending}
              className="w-full justify-start"
            >
              <AlertCircle size={15} aria-hidden="true" />
              Non — toujours en attente, lance les relances
            </Button>
          </div>

          {/* Footer : Plus tard + compteur restant */}
          <div className="mt-4 flex items-center justify-between gap-3">
            <button
              type="button"
              onClick={onSkip}
              disabled={isPending}
              className={cn(
                // Tap target ≥ 44pt — px-3 py-2.5 = 40-44px height
                "inline-flex items-center px-3 py-2.5 -ml-3 rounded-default cursor-pointer",
                "text-[13px] text-ink-3 hover:text-rubis transition-colors",
                "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-rubis-glow",
                "disabled:opacity-50 disabled:cursor-not-allowed",
              )}
            >
              Plus tard
            </button>
            {remaining > 0 && (
              <p className="text-[11.5px] text-ink-3 italic flex items-center gap-1 shrink-0">
                <ArrowRight size={11} aria-hidden="true" />
                {remaining} autre{remaining > 1 ? "s" : ""} après
              </p>
            )}
          </div>
        </DialogPrimitive.Content>
      </DialogPrimitive.Portal>
    </DialogPrimitive.Root>
  );
}

/**
 * Fiche récap de la facture — adaptée mobile.
 * Au lieu de flex-row amount/date qui squashe à 320px, on stacke
 * verticalement et on aligne tout à gauche pour la lisibilité pouce-only.
 */
function InvoiceCard({ invoice }: { invoice: PendingCheckinInvoice }) {
  const isLate = isOverdue(invoice.dueDate);
  const dueLabel = formatDueDelta(invoice.dueDate);

  return (
    <div className="rounded-card border border-line bg-white px-4 py-4">
      {/* Header — numéro + client */}
      <div className="flex items-center gap-2">
        <FileText size={14} className="text-ink-3 shrink-0" aria-hidden="true" />
        <p className="font-display text-[14.5px] font-semibold tracking-tight text-ink truncate">
          {invoice.numero}
        </p>
      </div>
      <p className="mt-0.5 text-[12.5px] text-ink-2 truncate">
        {invoice.clientName}
      </p>

      {/* Montant XL en feature */}
      <p className="mt-3 font-display text-[26px] font-bold tabular-nums leading-none text-ink">
        {formatEuros(invoice.amountTtcCents)}
      </p>

      {/* Date + retard, sur la même ligne mais avec wrap propre */}
      <div className="mt-2 flex flex-wrap items-baseline gap-x-3 gap-y-0.5 text-[12px]">
        <span className="inline-flex items-center gap-1 text-ink-3 tabular-nums">
          <Calendar size={11} aria-hidden="true" />
          échue le {formatDate(invoice.dueDate)}
        </span>
        <span
          className={cn(
            "font-medium tabular-nums",
            isLate ? "text-rubis-deep" : "text-ink-3",
          )}
        >
          ({dueLabel})
        </span>
      </div>

      {invoice.planName && (
        <p className="mt-3 pt-3 border-t border-line text-[11.5px] text-ink-3">
          Plan : <strong className="font-medium text-ink-2">{invoice.planName}</strong>
        </p>
      )}
    </div>
  );
}
