// src/components/keywords/keyword-sheet.tsx — « Keyword Detail » : modale
// centrée (ELEVA-80, remplace l'ancien drawer). Garde le nom/export/props
// historiques — consommée par reservoir, research-container, planning.
"use client";

import {
  CalendarPlus,
  Check,
  Clock,
  Copy,
  Download,
  Ellipsis,
  Search,
  Star,
  Trash2,
  XIcon,
} from "lucide-react";
import { useRouter } from "next/navigation";
import { useEffect, useMemo, useRef, useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogTitle,
} from "@/components/ui/dialog";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Flag } from "@/components/ui/flag";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  addKeywordsToStageAction,
  addToShortlistAction,
  deleteKeywordsAction,
  fetchShortlistAction,
  removeFromShortlistAction,
  removeKeywordFromStageAction,
  updateKeywordAction,
} from "@/lib/keywords/actions";
import {
  KEYWORD_STATUSES,
  type Keyword,
  type KeywordSource,
  type KeywordStatus,
  type KeywordTheme,
  type SearchIntent,
} from "@/lib/keywords/types";
import { cn } from "@/lib/utils";
import { BriefPanel } from "./brief-panel";
import { ExportEnrichmentDialog } from "./export-enrichment-dialog";
import { ImportBriefDialog } from "./import-brief-dialog";
import { KeywordModalKpis } from "./keyword-modal-kpis";
import { KeywordModalRankCard } from "./keyword-modal-rank-card";
import { KeywordModalSources } from "./keyword-modal-sources";
import { KeywordModalTrend } from "./keyword-modal-trend";
import { latestUpdatedAt, relativeFr } from "./keyword-modal-utils";
import { PromoteToContentDialog } from "./promote-content-dialog";
import { STATUS_LABELS, STATUS_STYLES } from "./status-badge";
import { ThemeSelect } from "./theme-select";

const INTENTS: SearchIntent[] = [
  "informational",
  "commercial",
  "transactional",
  "navigational",
  "local",
];
const INTENT_LABELS: Record<SearchIntent, string> = {
  informational: "Info",
  commercial: "Commercial",
  transactional: "Transac",
  navigational: "Navig",
  local: "Local",
};

// Status colors come from STATUS_STYLES (status-badge.tsx, the shared source of
// truth) so the modal header pill matches the table badge exactly (ELEVA-86).

function Field({
  label,
  children,
}: {
  label: string;
  children: React.ReactNode;
}) {
  return (
    <div className="flex flex-col gap-1.5">
      <span className="pl-0.5 font-semibold text-[10.5px] text-muted-foreground/70 uppercase tracking-wider">
        {label}
      </span>
      {children}
    </div>
  );
}

export function KeywordSheet({
  keyword,
  open,
  onOpenChange,
  siteId,
  onSaved,
  enableBriefs = false,
  source,
}: {
  keyword: Keyword | null;
  open: boolean;
  onOpenChange: (open: boolean) => void;
  siteId: string;
  onSaved: () => void;
  enableBriefs?: boolean;
  /** Active toolbar « Source » view — KPIs mirror this source (else primary). */
  source?: KeywordSource | "";
}) {
  const router = useRouter();
  const [status, setStatus] = useState<KeywordStatus>("idea");
  const [theme, setTheme] = useState<KeywordTheme | null>(null);
  const [intent, setIntent] = useState<SearchIntent[]>([]);
  /** « Promu » = le mot-clé est promu en Planning (badge P existant). */
  const [promoted, setPromoted] = useState(false);
  const [shortlisted, setShortlisted] = useState<boolean | null>(null);
  const [briefOpen, setBriefOpen] = useState(false);
  const [promoteOpen, setPromoteOpen] = useState(false);
  const [exportOpen, setExportOpen] = useState(false);

  const keywordId = keyword?.id;
  // Id du mot-clé actuellement ouvert — lu par le « Annuler » du toast de
  // statut (closure sur l'ancien id) pour ne resynchroniser le Select local
  // que si la fiche affiche encore le même mot-clé au moment du clic.
  const currentIdRef = useRef(keywordId);
  currentIdRef.current = keywordId;

  // Re-seed local edit state whenever a different keyword opens.
  // biome-ignore lint/correctness/useExhaustiveDependencies: reseed only when the opened keyword changes, not on every field mutation
  useEffect(() => {
    if (!keyword) return;
    setStatus(keyword.status);
    setTheme(keyword.theme);
    setIntent(keyword.intent);
    setPromoted(keyword.stages.includes("planning"));
  }, [keyword?.id]);

  // Shortlist state — fetched lazily when the modal opens (never on mount;
  // the component mounts closed, so this never races an RSC navigation).
  useEffect(() => {
    if (!open || !keywordId) return;
    let cancelled = false;
    setShortlisted(null);
    fetchShortlistAction(siteId)
      .then((items) => {
        if (!cancelled) setShortlisted(items.some((s) => s.id === keywordId));
      })
      .catch(() => {});
    return () => {
      cancelled = true;
    };
  }, [open, keywordId, siteId]);

  const promoteKeywords = useMemo(
    () => (keyword ? [{ id: keyword.id, term: keyword.term }] : []),
    [keyword],
  );
  const exportKeywords = useMemo(() => (keyword ? [keyword] : []), [keyword]);

  async function save(patch: {
    status?: KeywordStatus;
    theme?: KeywordTheme | null;
    intent?: SearchIntent[];
  }) {
    if (!keyword) return;
    const id = keyword.id;
    // Closure : le handler du Select fait `setStatus(s)` PUIS `save(...)`,
    // donc `status` vaut encore l'ancienne valeur ici.
    const prevStatus = status;
    try {
      await updateKeywordAction(siteId, id, patch);
      onSaved();
      // Undo sur le changement de statut (clic accidentel « Actif », etc.).
      // Thème/intents restent silencieux (toasts trop bavards au toggle).
      if (patch.status !== undefined && patch.status !== prevStatus) {
        toast.success(`Statut : ${STATUS_LABELS[patch.status]}`, {
          // Le défaut sonner (4 s) est trop court pour décider d'annuler.
          duration: 10_000,
          action: {
            label: "Annuler",
            onClick: () => {
              void updateKeywordAction(siteId, id, { status: prevStatus })
                .then(() => {
                  // Resynchronise le Select seulement si la fiche affiche
                  // encore CE mot-clé (elle a pu changer ou se fermer).
                  if (currentIdRef.current === id) setStatus(prevStatus);
                  onSaved();
                  toast.success(
                    `Statut rétabli : ${STATUS_LABELS[prevStatus]}`,
                  );
                })
                .catch(() => toast.error("Échec de l'annulation"));
            },
          },
        });
      }
    } catch {
      // swallow — matches the codebase's fire-and-forget convention (no toast infra)
    }
  }

  function toggleIntent(i: SearchIntent) {
    const next = intent.includes(i)
      ? intent.filter((x) => x !== i)
      : [...intent, i];
    setIntent(next);
    save({ intent: next });
  }

  async function togglePromoted() {
    if (!keyword) return;
    const next = !promoted;
    setPromoted(next);
    try {
      if (next) {
        await addKeywordsToStageAction(siteId, [keyword.id], "planning");
      } else {
        await removeKeywordFromStageAction(siteId, keyword.id, "planning");
      }
      onSaved();
    } catch {
      setPromoted(!next);
      toast.error("Échec de la mise à jour");
    }
  }

  async function toggleShortlist() {
    if (!keyword || shortlisted === null) return;
    const next = !shortlisted;
    setShortlisted(next);
    try {
      if (next) {
        await addToShortlistAction(siteId, [keyword.id]);
        toast.success("Marqué prioritaire (shortlist)");
      } else {
        await removeFromShortlistAction(siteId, [keyword.id]);
        toast.success("Retiré de la shortlist");
      }
    } catch {
      setShortlisted(!next);
      toast.error("Échec de la mise à jour de la shortlist");
    }
  }

  async function deleteKeyword() {
    if (!keyword) return;
    try {
      await deleteKeywordsAction(siteId, [keyword.id]);
      toast.success("Mot-clé supprimé");
      onOpenChange(false);
      onSaved();
    } catch {
      toast.error("Échec de la suppression");
    }
  }

  const updated = keyword ? relativeFr(latestUpdatedAt(keyword)) : null;

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent
        showCloseButton={false}
        className="flex max-h-[min(900px,calc(100vh-56px))] w-[min(940px,calc(100vw-56px))] max-w-none flex-col gap-0 overflow-hidden rounded-[22px] p-0 shadow-2xl sm:max-w-none dark:bg-[linear-gradient(180deg,#121216_0%,#0e0e11_100%)]"
      >
        {keyword ? (
          <>
            {/* ---------- Header ---------- */}
            <header className="border-border/60 border-b px-6 pt-5 pb-4">
              <div className="flex items-start justify-between gap-4">
                <div className="flex min-w-0 flex-col gap-2.5">
                  <nav
                    aria-label="Fil d'Ariane"
                    className="flex items-center gap-2 font-medium text-[12.5px] text-muted-foreground"
                  >
                    <span>Keywords</span>
                    <span className="size-[3px] rounded-full bg-muted-foreground/50" />
                    <span>{enableBriefs ? "Recherche" : "Réservoir"}</span>
                    <span className="size-[3px] rounded-full bg-muted-foreground/50" />
                    <span>Détail</span>
                  </nav>
                  <div className="flex flex-wrap items-center gap-3">
                    <DialogTitle className="font-semibold text-[25px] leading-tight tracking-tight">
                      {keyword.term}
                    </DialogTitle>
                    <span className="inline-flex h-[25px] items-center gap-1.5 rounded-full border border-border/70 bg-muted/40 px-2.5 font-medium text-muted-foreground text-xs">
                      <Flag code={keyword.locale.country} />
                      {keyword.locale.lang}-{keyword.locale.country}
                    </span>
                    <span
                      className={cn(
                        "inline-flex h-[25px] items-center gap-1.5 rounded-full border px-2.5 font-semibold text-xs",
                        STATUS_STYLES[status].pill,
                      )}
                    >
                      <span
                        className={cn(
                          "size-1.5 rounded-full",
                          STATUS_STYLES[status].dot,
                        )}
                      />
                      {STATUS_LABELS[status]}
                    </span>
                    {keyword.stages.includes("research") ? (
                      <span
                        title="Promu en Recherche"
                        className="inline-flex h-[25px] items-center rounded-full border border-border bg-muted/40 px-2.5 font-semibold text-muted-foreground text-xs"
                      >
                        R
                      </span>
                    ) : null}
                  </div>
                  <DialogDescription className="sr-only">
                    Détail du mot-clé {keyword.term} — édition, métriques et
                    actions SEO.
                  </DialogDescription>
                </div>

                <div className="flex flex-none items-center gap-2">
                  <Button
                    variant="outline"
                    size="icon"
                    onClick={togglePromoted}
                    aria-pressed={promoted}
                    title={promoted ? "Promu — retirer" : "Promouvoir"}
                    className={cn(
                      promoted
                        ? "border-amber-500/30 bg-amber-500/10 text-amber-400 hover:bg-amber-500/15 hover:text-amber-400"
                        : "text-muted-foreground",
                    )}
                  >
                    <Star className={promoted ? "fill-current" : undefined} />
                    <span className="sr-only">Promu</span>
                  </Button>
                  <DropdownMenu>
                    <DropdownMenuTrigger asChild>
                      <Button
                        variant="outline"
                        size="icon"
                        className="text-muted-foreground"
                        title="Plus d'actions"
                      >
                        <Ellipsis />
                        <span className="sr-only">Plus d'actions</span>
                      </Button>
                    </DropdownMenuTrigger>
                    <DropdownMenuContent align="end">
                      <DropdownMenuItem
                        onClick={() => {
                          void navigator.clipboard
                            .writeText(keyword.term)
                            .then(() => toast.success("Terme copié"));
                        }}
                      >
                        <Copy /> Copier le terme
                      </DropdownMenuItem>
                      <DropdownMenuItem onClick={() => setExportOpen(true)}>
                        <Download /> Exporter pour enrichissement
                      </DropdownMenuItem>
                      <DropdownMenuItem
                        variant="destructive"
                        onClick={deleteKeyword}
                      >
                        <Trash2 /> Supprimer
                      </DropdownMenuItem>
                    </DropdownMenuContent>
                  </DropdownMenu>
                  <DialogClose asChild>
                    <Button
                      variant="outline"
                      size="icon"
                      className="text-muted-foreground"
                      title="Fermer"
                    >
                      <XIcon />
                      <span className="sr-only">Fermer</span>
                    </Button>
                  </DialogClose>
                </div>
              </div>

              {/* ---------- Quick-edit toolbar ---------- */}
              <div className="mt-4 flex flex-wrap items-end gap-2.5">
                <Field label="Statut">
                  <Select
                    value={status}
                    onValueChange={(v) => {
                      const s = v as KeywordStatus;
                      setStatus(s);
                      save({ status: s });
                    }}
                  >
                    <SelectTrigger
                      size="sm"
                      className="min-w-[130px]"
                      aria-label="Statut"
                    >
                      <span
                        className={cn(
                          "size-[7px] shrink-0 rounded-full",
                          STATUS_STYLES[status].dot,
                        )}
                        aria-hidden="true"
                      />
                      <SelectValue />
                    </SelectTrigger>
                    <SelectContent position="popper">
                      {KEYWORD_STATUSES.map((s) => (
                        <SelectItem key={s} value={s}>
                          {STATUS_LABELS[s]}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                </Field>

                <Field label="Thème">
                  <ThemeSelect
                    value={theme}
                    onChange={(t) => {
                      setTheme(t);
                      save({ theme: t });
                    }}
                    triggerSize="sm"
                    className="min-w-[150px]"
                  />
                </Field>

                <fieldset className="flex flex-col gap-1.5 border-0 p-0">
                  <legend className="pl-0.5 font-semibold text-[10.5px] text-muted-foreground/70 uppercase tracking-wider">
                    Intent
                  </legend>
                  <div className="inline-flex h-8 items-center gap-0.5 rounded-[11px] border border-border/60 bg-muted/30 p-0.5">
                    {INTENTS.map((i) => {
                      const on = intent.includes(i);
                      return (
                        <button
                          key={i}
                          type="button"
                          onClick={() => toggleIntent(i)}
                          aria-pressed={on}
                          className={cn(
                            "h-[26px] rounded-lg px-3 font-medium text-xs transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
                            on
                              ? "bg-primary text-primary-foreground shadow-sm"
                              : "text-muted-foreground hover:text-foreground",
                          )}
                        >
                          {INTENT_LABELS[i]}
                        </button>
                      );
                    })}
                  </div>
                </fieldset>

                <div className="flex-1" />

                <button
                  type="button"
                  role="switch"
                  aria-checked={promoted}
                  onClick={togglePromoted}
                  className="inline-flex h-8 items-center gap-2 rounded-[10px] border border-border/60 bg-muted/30 px-3 font-medium text-[13px] text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
                >
                  <span
                    className={cn(
                      "relative h-[18px] w-8 flex-none rounded-full transition-colors",
                      promoted ? "bg-primary" : "bg-muted-foreground/30",
                    )}
                  >
                    <span
                      className={cn(
                        "absolute top-0.5 left-0.5 size-3.5 rounded-full bg-background transition-transform",
                        promoted && "translate-x-3.5",
                      )}
                    />
                  </span>
                  Promu
                </button>
              </div>
            </header>

            {/* ---------- Body ---------- */}
            <div className="flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto px-6 py-4">
              <KeywordModalKpis keyword={keyword} source={source} />

              {/* Brief YTG (contenu + grammage : top terms / entités / n-grams)
                  placé haut — c'est l'info clé pour la rédaction. */}
              {enableBriefs ? (
                <section className="flex flex-col gap-3 rounded-2xl border border-border/70 bg-card px-4.5 py-4">
                  <div className="flex items-center justify-between gap-2">
                    <h3 className="font-semibold text-[11px] text-muted-foreground/80 uppercase tracking-wider">
                      Briefs YTG
                    </h3>
                    <Button
                      size="sm"
                      variant="outline"
                      onClick={() => setBriefOpen(true)}
                    >
                      Importer un brief
                    </Button>
                  </div>
                  {Object.keys(keyword.briefs).length === 0 ? (
                    <p className="text-muted-foreground text-xs italic">
                      Aucun brief importé.
                    </p>
                  ) : (
                    <BriefPanel briefs={keyword.briefs} />
                  )}
                </section>
              ) : null}

              <KeywordModalTrend keyword={keyword} source={source} />
              <div className="grid items-stretch gap-3.5 lg:grid-cols-[1.15fr_0.85fr]">
                <KeywordModalRankCard keyword={keyword} />
                <KeywordModalSources keyword={keyword} />
              </div>
            </div>

            {/* ---------- Footer ---------- */}
            <footer className="flex flex-wrap items-center gap-2.5 border-border/60 border-t px-6 py-3.5">
              <Button onClick={() => setPromoteOpen(true)}>
                <CalendarPlus /> Planifier du contenu
              </Button>
              <Button
                variant="outline"
                onClick={toggleShortlist}
                disabled={shortlisted === null}
                aria-pressed={shortlisted === true}
                className={cn(
                  shortlisted &&
                    "border-emerald-500/30 bg-emerald-500/10 text-emerald-400 hover:bg-emerald-500/15 hover:text-emerald-400",
                )}
              >
                <Check /> {shortlisted ? "Prioritaire" : "Marquer prioritaire"}
              </Button>
              <Button
                variant="outline"
                onClick={() => {
                  onOpenChange(false);
                  router.push(
                    `/keywords/recherche?q=${encodeURIComponent(keyword.term)}`,
                  );
                }}
              >
                <Search /> Voir la recherche
              </Button>
              <div className="flex-1" />
              {updated ? (
                <span className="inline-flex items-center gap-1.5 text-[11px] text-muted-foreground/80">
                  <Clock className="size-3.5" aria-hidden="true" />
                  Maj. {updated}
                </span>
              ) : null}
            </footer>

            {/* ---------- Nested dialogs ---------- */}
            <PromoteToContentDialog
              siteId={siteId}
              keywords={promoteKeywords}
              open={promoteOpen}
              onOpenChange={setPromoteOpen}
              onDone={onSaved}
            />
            <ExportEnrichmentDialog
              open={exportOpen}
              onOpenChange={setExportOpen}
              keywords={exportKeywords}
              siteId={siteId}
              scoped
              onMarked={onSaved}
            />
            {enableBriefs ? (
              <ImportBriefDialog
                open={briefOpen}
                onOpenChange={setBriefOpen}
                siteId={siteId}
                keywordId={keyword.id}
                onImported={() => {
                  setBriefOpen(false);
                  onSaved();
                }}
              />
            ) : null}
          </>
        ) : null}
      </DialogContent>
    </Dialog>
  );
}
