"use client";

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useRef,
  useState,
} from "react";
import { createPortal } from "react-dom";
import Icon from "@/components/Icon";

/**
 * Système unifié de dialogues bloquants (confirm) + toasts non-bloquants.
 *
 * Remplace les `window.confirm()` / `window.alert()` natifs par un design
 * cohérent avec le reste du site (Sovereign Precision : noir / or, serif
 * uppercase tracking, angles francs).
 *
 * Usage :
 *   const { confirm, toast } = useDialog();
 *   const ok = await confirm({ title: "Supprimer ?", body: "...", danger: true });
 *   if (!ok) return;
 *   toast({ message: "Supprimé.", variant: "success" });
 *
 * Le provider doit envelopper les pages où l'on utilise le hook. On le mount
 * dans `<Shell>` pour couvrir admin + client en un seul endroit.
 */

export type ConfirmOpts = {
  title: string;
  body?: string;
  confirmLabel?: string;
  cancelLabel?: string;
  /** Style "destructif" : bouton rouge, icône warning. */
  danger?: boolean;
};

export type ToastVariant = "info" | "success" | "error";

export type ToastOpts =
  | string
  | {
      message: string;
      title?: string;
      variant?: ToastVariant;
      /** ms avant auto-dismiss, default 5000. 0 = sticky. */
      duration?: number;
    };

type Toast = {
  id: number;
  message: string;
  title?: string;
  variant: ToastVariant;
};

type DialogContextValue = {
  confirm: (opts: ConfirmOpts) => Promise<boolean>;
  toast: (opts: ToastOpts) => void;
};

const DialogContext = createContext<DialogContextValue | null>(null);

export function useDialog(): DialogContextValue {
  const ctx = useContext(DialogContext);
  if (!ctx) {
    throw new Error(
      "useDialog() must be used within a <DialogProvider>. Mount it in your layout (Shell already does)."
    );
  }
  return ctx;
}

type ConfirmState =
  | (ConfirmOpts & { resolve: (v: boolean) => void })
  | null;

export default function DialogProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  const [confirmState, setConfirmState] = useState<ConfirmState>(null);
  const [toasts, setToasts] = useState<Toast[]>([]);
  const nextId = useRef(0);
  const [mounted, setMounted] = useState(false);

  useEffect(() => setMounted(true), []);

  const confirm = useCallback(
    (opts: ConfirmOpts) =>
      new Promise<boolean>((resolve) => {
        setConfirmState({ ...opts, resolve });
      }),
    []
  );

  const dismissConfirm = useCallback((value: boolean) => {
    setConfirmState((prev) => {
      if (!prev) return null;
      prev.resolve(value);
      return null;
    });
  }, []);

  const toast = useCallback((opts: ToastOpts) => {
    const norm =
      typeof opts === "string"
        ? { message: opts, variant: "info" as ToastVariant }
        : { variant: "info" as ToastVariant, ...opts };
    const id = nextId.current++;
    const t: Toast = {
      id,
      message: norm.message,
      title: norm.title,
      variant: norm.variant ?? "info",
    };
    setToasts((prev) => [...prev, t]);
    const duration =
      typeof opts === "string" ? 5000 : opts.duration ?? 5000;
    if (duration > 0) {
      setTimeout(() => {
        setToasts((prev) => prev.filter((x) => x.id !== id));
      }, duration);
    }
  }, []);

  const dismissToast = useCallback((id: number) => {
    setToasts((prev) => prev.filter((t) => t.id !== id));
  }, []);

  return (
    <DialogContext.Provider value={{ confirm, toast }}>
      {children}
      {mounted &&
        createPortal(
          <>
            {confirmState && (
              <ConfirmModal
                opts={confirmState}
                onResolve={dismissConfirm}
              />
            )}
            <Toaster toasts={toasts} onDismiss={dismissToast} />
          </>,
          document.body
        )}
    </DialogContext.Provider>
  );
}

/* ─── Confirm Modal ─────────────────────────────────────────────────── */

function ConfirmModal({
  opts,
  onResolve,
}: {
  opts: ConfirmOpts;
  onResolve: (v: boolean) => void;
}) {
  const cancelRef = useRef<HTMLButtonElement | null>(null);
  const confirmRef = useRef<HTMLButtonElement | null>(null);

  // Focus initial sur cancel (sécu : on ne valide pas par défaut une action
  // destructive). Trap basique : Escape annule, Enter sur confirm valide.
  useEffect(() => {
    cancelRef.current?.focus();
    function onKey(e: KeyboardEvent) {
      if (e.key === "Escape") {
        e.preventDefault();
        onResolve(false);
      } else if (e.key === "Tab") {
        // mini focus trap
        const focusables = [cancelRef.current, confirmRef.current].filter(
          Boolean
        ) as HTMLElement[];
        if (focusables.length === 0) return;
        const active = document.activeElement as HTMLElement | null;
        const idx = focusables.indexOf(active as HTMLElement);
        e.preventDefault();
        const next = e.shiftKey
          ? focusables[(idx - 1 + focusables.length) % focusables.length]
          : focusables[(idx + 1) % focusables.length];
        next.focus();
      }
    }
    document.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => {
      document.removeEventListener("keydown", onKey);
      document.body.style.overflow = "";
    };
  }, [onResolve]);

  return (
    <div
      role="dialog"
      aria-modal="true"
      aria-labelledby="dialog-title"
      className="fixed inset-0 z-[1000] flex items-center justify-center px-4"
      style={{ backgroundColor: "rgba(20, 28, 37, 0.55)" }}
      onClick={(e) => {
        if (e.target === e.currentTarget) onResolve(false);
      }}
    >
      <div
        className="bg-white border border-outline-variant w-full max-w-md shadow-2xl"
        style={{
          boxShadow:
            "0 20px 60px rgba(0, 0, 0, 0.18), 0 8px 20px rgba(0, 0, 0, 0.06)",
        }}
      >
        <header className="flex items-start gap-4 p-8 border-b border-outline-variant/40">
          <span
            className="inline-flex shrink-0 items-center justify-center w-10 h-10 mt-1"
            style={{
              backgroundColor: opts.danger
                ? "rgba(186, 26, 26, 0.08)"
                : "rgba(119, 90, 25, 0.10)",
            }}
          >
            <Icon
              name={opts.danger ? "warning" : "help"}
              className={`!text-xl ${
                opts.danger ? "text-error" : "text-secondary"
              }`}
              filled={!opts.danger}
            />
          </span>
          <div className="min-w-0 flex-1">
            <span className="eyebrow !text-secondary block mb-1">
              {opts.danger ? "Action destructive" : "Confirmation"}
            </span>
            <h2
              id="dialog-title"
              className="font-serif text-xl text-primary leading-tight"
            >
              {opts.title}
            </h2>
          </div>
        </header>

        {opts.body && (
          <div className="px-8 py-6">
            <p className="body-md text-on-surface-variant whitespace-pre-line">
              {opts.body}
            </p>
          </div>
        )}

        <footer className="flex items-center justify-end gap-2 px-8 py-5 bg-surface-container-low border-t border-outline-variant/40">
          <button
            ref={cancelRef}
            type="button"
            onClick={() => onResolve(false)}
            className="text-xs uppercase tracking-widest font-serif px-4 py-2.5 text-on-surface-variant hover:text-primary transition-colors"
          >
            {opts.cancelLabel ?? "Annuler"}
          </button>
          <button
            ref={confirmRef}
            type="button"
            onClick={() => onResolve(true)}
            autoFocus={!opts.danger}
            className={
              opts.danger
                ? "text-xs uppercase tracking-widest font-serif px-5 py-2.5 border border-error text-error hover:bg-error hover:text-on-error transition-colors"
                : "btn btn-primary !py-2.5 text-xs"
            }
          >
            {opts.confirmLabel ?? (opts.danger ? "Supprimer" : "Confirmer")}
          </button>
        </footer>
      </div>
    </div>
  );
}

/* ─── Toaster ───────────────────────────────────────────────────────── */

function Toaster({
  toasts,
  onDismiss,
}: {
  toasts: Toast[];
  onDismiss: (id: number) => void;
}) {
  if (toasts.length === 0) return null;
  return (
    <div
      aria-live="polite"
      aria-atomic="true"
      className="fixed bottom-6 right-6 z-[1100] flex flex-col gap-3 max-w-sm w-[calc(100%-3rem)]"
    >
      {toasts.map((t) => (
        <ToastItem key={t.id} toast={t} onDismiss={() => onDismiss(t.id)} />
      ))}
    </div>
  );
}

function ToastItem({
  toast,
  onDismiss,
}: {
  toast: Toast;
  onDismiss: () => void;
}) {
  const config: Record<
    ToastVariant,
    { icon: string; borderCls: string; iconCls: string; eyebrow: string }
  > = {
    info: {
      icon: "info",
      borderCls: "border-l-secondary",
      iconCls: "text-secondary",
      eyebrow: "Info",
    },
    success: {
      icon: "check_circle",
      borderCls: "border-l-primary",
      iconCls: "text-primary",
      eyebrow: "Succès",
    },
    error: {
      icon: "error",
      borderCls: "border-l-error",
      iconCls: "text-error",
      eyebrow: "Erreur",
    },
  };
  const c = config[toast.variant];
  return (
    <div
      role={toast.variant === "error" ? "alert" : "status"}
      className={`bg-white border border-outline-variant ${c.borderCls} border-l-4 px-5 py-4 flex items-start gap-3 shadow-lg animate-toast-in`}
      style={{
        boxShadow: "0 12px 32px rgba(0, 0, 0, 0.12)",
      }}
    >
      <Icon
        name={c.icon}
        className={`!text-xl ${c.iconCls} mt-0.5 shrink-0`}
        filled
      />
      <div className="min-w-0 flex-1">
        <p
          className={`text-[10px] uppercase tracking-widest font-serif ${c.iconCls} mb-1`}
        >
          {toast.title ?? c.eyebrow}
        </p>
        <p className="body-md text-on-surface leading-snug">
          {toast.message}
        </p>
      </div>
      <button
        type="button"
        onClick={onDismiss}
        aria-label="Fermer"
        className="text-on-surface-variant hover:text-primary transition-colors p-1 -m-1 shrink-0"
      >
        <Icon name="close" className="!text-base" />
      </button>
    </div>
  );
}
