"use client";

import Image from "next/image";
import Link from "next/link";
import { useRef, useState, useTransition } from "react";
import {
  ArrowLeft,
  ArrowUpRight,
  Camera,
  Gauge,
  Loader2,
  Pencil,
  Plus,
  Save,
  Sparkles,
  Trash2,
  Upload,
  Wand2,
  X,
} from "@/components/ui/icons";
import { Topbar } from "@/components/shell/topbar";
import { Panel } from "@/components/ui/panel";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { toast } from "@/components/ui/toast";
import {
  LIGHTHOUSE_LABELS,
  PROJECT_TYPES,
  TYPE_LABELS,
  emptyRealisation,
  type LighthouseScores,
  type PageSpeedData,
  type Realisation,
} from "@/lib/realisations";
import {
  analyseSite,
  deleteRealisation,
  fetchPageSpeed,
  generatePresentation,
  recaptureScreenshot,
  saveRealisation,
  uploadScreenshot,
} from "./actions";

type Mode = { kind: "list" } | { kind: "edit"; original: string | null; data: Realisation };

export function RealisationsManager({ initial }: { initial: Realisation[] }) {
  const [items, setItems] = useState<Realisation[]>(initial);
  const [mode, setMode] = useState<Mode>({ kind: "list" });

  function startCreate() {
    setMode({ kind: "edit", original: null, data: emptyRealisation() });
  }
  function startEdit(r: Realisation) {
    setMode({ kind: "edit", original: r.slug, data: structuredClone(r) });
  }
  function backToList() {
    setMode({ kind: "list" });
  }

  function refreshAfterSave(saved: Realisation, originalSlug: string | null) {
    setItems((prev) => {
      if (originalSlug) {
        return prev.map((r) => (r.slug === originalSlug ? saved : r));
      }
      return [saved, ...prev];
    });
    backToList();
  }

  function refreshAfterDelete(slug: string) {
    setItems((prev) => prev.filter((r) => r.slug !== slug));
  }

  if (mode.kind === "edit") {
    return (
      <RealisationForm
        initial={mode.data}
        originalSlug={mode.original}
        onCancel={backToList}
        onSaved={(saved) => refreshAfterSave(saved, mode.original)}
      />
    );
  }

  return (
    <RealisationsList
      items={items}
      onCreate={startCreate}
      onEdit={startEdit}
      onDeleted={refreshAfterDelete}
    />
  );
}

// ---------------- LIST ----------------

function RealisationsList({
  items,
  onCreate,
  onEdit,
  onDeleted,
}: {
  items: Realisation[];
  onCreate: () => void;
  onEdit: (r: Realisation) => void;
  onDeleted: (slug: string) => void;
}) {
  return (
    <>
      <Topbar
        title="Réalisations"
        subtitle={`${items.length} projet${items.length > 1 ? "s" : ""} publié${items.length > 1 ? "s" : ""}`}
        trailing={
          <Button variant="primary" size="sm" onClick={onCreate}>
            <Plus className="size-3.5" />
            Ajouter un projet
          </Button>
        }
      />

      <div className="pt-6">
        {items.length === 0 ? (
          <Panel className="p-12 text-center">
            <div className="mx-auto size-12 rounded-full border border-border bg-stone-900/[0.03] flex items-center justify-center">
              <Plus className="size-5 text-text-dim" />
            </div>
            <p className="mt-4 font-editorial text-2xl font-medium text-text">
              Aucun projet publié.
            </p>
            <p className="mt-2 text-sm text-text-muted max-w-md mx-auto">
              Ajoutez votre premier projet en collant son URL. Captures et description
              seront générées automatiquement, à corriger ensuite.
            </p>
            <div className="mt-6">
              <Button variant="primary" size="md" onClick={onCreate}>
                <Plus className="size-3.5" />
                Ajouter un projet
              </Button>
            </div>
          </Panel>
        ) : (
          <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
            {items.map((r) => (
              <RealisationListCard
                key={r.slug}
                r={r}
                onEdit={() => onEdit(r)}
                onDeleted={() => onDeleted(r.slug)}
              />
            ))}
          </div>
        )}
      </div>
    </>
  );
}

function RealisationListCard({
  r,
  onEdit,
  onDeleted,
}: {
  r: Realisation;
  onEdit: () => void;
  onDeleted: () => void;
}) {
  const [pending, startTransition] = useTransition();
  const [confirming, setConfirming] = useState(false);

  function handleDelete() {
    if (!confirming) {
      setConfirming(true);
      setTimeout(() => setConfirming(false), 4000);
      return;
    }
    startTransition(async () => {
      const res = await deleteRealisation(r.slug);
      if (res.ok) {
        toast.success(`"${r.name}" supprimee.`);
        onDeleted();
      } else {
        toast.error(res.error ?? "Suppression echouee.");
      }
    });
  }

  return (
    <Panel className="overflow-hidden flex flex-col">
      <div className="relative aspect-video bg-surface-2 border-b border-border">
        {r.desktopScreenshot ? (
          <Image
            src={r.desktopScreenshot}
            alt={r.name}
            fill
            sizes="(min-width: 1280px) 33vw, (min-width: 768px) 50vw, 100vw"
            className="object-cover object-top"
          />
        ) : (
          <div className="absolute inset-0 flex items-center justify-center text-text-faint text-xs">
            Aucune capture
          </div>
        )}
        <div className="absolute top-2 left-2">
          <Badge tone="muted">{TYPE_LABELS[r.type]}</Badge>
        </div>
      </div>

      <div className="p-5 flex-1 flex flex-col">
        <div className="flex items-start justify-between gap-3">
          <div className="min-w-0">
            <h3 className="font-editorial text-lg font-medium text-text truncate">{r.name}</h3>
            <p className="text-xs text-text-muted truncate">
              {r.domain} · {r.sector}
            </p>
          </div>
          <span className="text-micro text-text-faint tabular-nums">{r.year}</span>
        </div>

        <p className="mt-3 text-xs text-text-muted line-clamp-2 leading-relaxed">{r.summary}</p>

        <div className="mt-5 flex items-center justify-between gap-2">
          <div className="flex items-center gap-1.5">
            <Button variant="outline" size="sm" onClick={onEdit}>
              <Pencil className="size-3" />
              Éditer
            </Button>
            <Link href={`/realisations/${r.slug}`} target="_blank">
              <Button variant="ghost" size="sm">
                <ArrowUpRight className="size-3" />
                Voir
              </Button>
            </Link>
          </div>
          <button
            type="button"
            onClick={handleDelete}
            disabled={pending}
            className="inline-flex items-center gap-1 text-xs text-text-faint hover:text-danger transition-colors disabled:opacity-50"
          >
            {pending ? (
              <Loader2 className="size-3 animate-spin" />
            ) : (
              <Trash2 className="size-3" />
            )}
            {confirming ? "Confirmer ?" : "Supprimer"}
          </button>
        </div>
      </div>
    </Panel>
  );
}

// ---------------- FORM ----------------

function RealisationForm({
  initial,
  originalSlug,
  onCancel,
  onSaved,
}: {
  initial: Realisation;
  originalSlug: string | null;
  onCancel: () => void;
  onSaved: (saved: Realisation) => void;
}) {
  const [data, setData] = useState<Realisation>(initial);
  const [urlDraft, setUrlDraft] = useState(initial.url);
  const [analysing, setAnalysing] = useState(false);
  const [saving, setSaving] = useState(false);
  const [recapture, setRecapture] = useState<{ desktop: boolean; mobile: boolean }>({
    desktop: false,
    mobile: false,
  });
  const [pagespeedFetching, setPagespeedFetching] = useState(false);
  const [generating, setGenerating] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [info, setInfo] = useState<string | null>(null);

  function patch<K extends keyof Realisation>(key: K, value: Realisation[K]) {
    setData((d) => ({ ...d, [key]: value }));
  }

  async function runAnalyse() {
    if (!urlDraft.trim()) {
      setError("Renseignez une URL avant d'analyser.");
      return;
    }
    setAnalysing(true);
    setError(null);
    setInfo(null);
    try {
      const res = await analyseSite(urlDraft.trim());
      if (!res.ok) {
        setError(res.error);
        return;
      }
      setData((d) => ({
        ...d,
        slug: d.slug || res.data.slug || d.slug,
        name: d.name || res.data.name || "",
        domain: res.data.domain ?? d.domain,
        url: res.data.url ?? d.url,
        year: res.data.year ?? d.year,
        summary: d.summary || res.data.summary || "",
        desktopScreenshot: res.data.desktopScreenshot ?? d.desktopScreenshot,
        mobileScreenshot: res.data.mobileScreenshot ?? d.mobileScreenshot,
      }));
      if (!res.data.desktopScreenshot || !res.data.mobileScreenshot) {
        setInfo(
          "Une ou plusieurs captures n'ont pas pu être faites. Réessayez avec « Re-capturer », ou téléversez une image.",
        );
      }
    } catch (e) {
      setError(
        e instanceof Error ? `Échec de l'analyse : ${e.message}` : "Échec de l'analyse.",
      );
    } finally {
      setAnalysing(false);
    }
  }

  async function runRecapture(variant: "desktop" | "mobile") {
    if (!data.url || !data.slug) {
      setError("URL et slug requis pour re-capturer.");
      return;
    }
    setRecapture((r) => ({ ...r, [variant]: true }));
    setError(null);
    setInfo(null);
    try {
      const res = await recaptureScreenshot(data.url, variant, data.slug);
      if (!res.ok) {
        setError(res.error);
        return;
      }
      if (variant === "desktop") {
        patch("desktopScreenshot", res.path);
      } else {
        patch("mobileScreenshot", res.path);
      }
    } catch (e) {
      setError(
        e instanceof Error
          ? `Échec de la capture : ${e.message}`
          : "Échec de la capture.",
      );
    } finally {
      setRecapture((r) => ({ ...r, [variant]: false }));
    }
  }

  async function runUpload(variant: "desktop" | "mobile", file: File) {
    if (!data.slug) {
      setError("Renseignez un slug avant d'envoyer un fichier.");
      return;
    }
    if (file.size > 10 * 1024 * 1024) {
      setError(
        `Image trop lourde (${(file.size / 1024 / 1024).toFixed(1)} MB). Limite : 10 MB.`,
      );
      return;
    }
    setRecapture((r) => ({ ...r, [variant]: true }));
    setError(null);
    setInfo(null);
    try {
      const fd = new FormData();
      fd.append("slug", data.slug);
      fd.append("variant", variant);
      fd.append("file", file);
      const res = await uploadScreenshot(fd);
      if (!res.ok) {
        setError(res.error);
        return;
      }
      if (variant === "desktop") {
        patch("desktopScreenshot", res.path);
      } else {
        patch("mobileScreenshot", res.path);
      }
    } catch (e) {
      setError(
        e instanceof Error
          ? `Échec de l'upload : ${e.message}`
          : "Échec de l'upload.",
      );
    } finally {
      setRecapture((r) => ({ ...r, [variant]: false }));
    }
  }

  async function runGenerate() {
    if (!data.url.trim()) {
      setError("URL requise pour générer la présentation.");
      return;
    }
    setGenerating(true);
    setError(null);
    setInfo(null);
    try {
      const res = await generatePresentation({
        url: data.url.trim(),
        existing: {
          name: data.name,
          domain: data.domain,
          sector: data.sector,
          summary: data.summary,
        },
      });
      if (!res.ok) {
        setError(res.error);
        return;
      }
      // Fusion non destructive : on ne remplit que les champs vides du form,
      // pour ne pas écraser ce que l'utilisateur a déjà saisi.
      setData((d) => ({
        ...d,
        tagline: d.tagline.trim() || res.data.tagline || d.tagline,
        brief: d.brief.trim() || res.data.brief || d.brief,
        sector: d.sector.trim() || res.data.sector || d.sector,
        context: d.context.trim() || res.data.context || d.context,
        type: d.type !== "vitrine" ? d.type : res.data.type ?? d.type,
        delivered:
          d.delivered.length > 0
            ? d.delivered
            : res.data.delivered ?? d.delivered,
        highlights:
          d.highlights.length > 0
            ? d.highlights
            : res.data.highlights ?? d.highlights,
      }));
      setInfo(
        "Présentation générée. Relisez et corrigez ce qui ne colle pas, surtout « Ce qu'on a livré » qui est déduit du site visible.",
      );
    } catch (e) {
      setError(
        e instanceof Error ? `Échec de la génération : ${e.message}` : "Échec de la génération.",
      );
    } finally {
      setGenerating(false);
    }
  }

  async function runFetchPageSpeed() {
    if (!data.url.trim()) {
      setError("URL requise pour mesurer PageSpeed.");
      return;
    }
    setPagespeedFetching(true);
    setError(null);
    setInfo(null);
    try {
      const res = await fetchPageSpeed(data.url.trim());
      if (!res.ok) {
        setError(res.error);
        return;
      }
      patch("pagespeed", res.data);
      if (!res.data.mobile || !res.data.desktop) {
        setInfo(
          "Une stratégie n'a pas répondu (rate limit Google possible). Complétez à la main si besoin.",
        );
      }
    } catch (e) {
      setError(
        e instanceof Error
          ? `Échec de la mesure : ${e.message}`
          : "Échec de la mesure PageSpeed.",
      );
    } finally {
      setPagespeedFetching(false);
    }
  }

  function patchPageSpeed(strategy: "mobile" | "desktop", scores: LighthouseScores | undefined) {
    setData((d) => {
      const next: PageSpeedData = { ...(d.pagespeed ?? {}) };
      if (scores) next[strategy] = scores;
      else delete next[strategy];
      const hasAny = next.mobile || next.desktop;
      return { ...d, pagespeed: hasAny ? next : undefined };
    });
  }

  function patchPageSpeedScore(
    strategy: "mobile" | "desktop",
    key: keyof LighthouseScores,
    value: number,
  ) {
    setData((d) => {
      const current: LighthouseScores = d.pagespeed?.[strategy] ?? {
        performance: 0,
        accessibility: 0,
        bestPractices: 0,
        seo: 0,
      };
      const next: PageSpeedData = {
        ...(d.pagespeed ?? {}),
        [strategy]: { ...current, [key]: value },
      };
      return { ...d, pagespeed: next };
    });
  }

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    setSaving(true);
    setError(null);
    const cleaned: Realisation = {
      ...data,
      slug: data.slug.trim(),
      name: data.name.trim(),
      domain: data.domain.trim(),
      url: data.url.trim(),
      sector: data.sector.trim(),
      context: data.context.trim(),
      tagline: data.tagline.trim(),
      summary: data.summary.trim(),
      brief: data.brief.trim(),
      delivered: data.delivered.map((s) => s.trim()).filter(Boolean),
      highlights: data.highlights
        .map((h) => ({ label: h.label.trim(), value: h.value.trim() }))
        .filter((h) => h.label && h.value),
      desktopScreenshot: stripCacheBust(data.desktopScreenshot),
      mobileScreenshot: stripCacheBust(data.mobileScreenshot),
    };
    const res = await saveRealisation(cleaned, originalSlug ?? undefined);
    setSaving(false);
    if (!res.ok) {
      setError(res.error);
      toast.error(res.error);
      return;
    }
    toast.success(`"${cleaned.name}" enregistree.`);
    onSaved(cleaned);
  }

  return (
    <>
      <Topbar
        title={originalSlug ? `Éditer · ${initial.name}` : "Nouveau projet"}
        subtitle={
          originalSlug
            ? "Modifiez les informations ou re-capturez les visuels."
            : "Collez l'URL du site, on tente de remplir le reste automatiquement."
        }
        trailing={
          <Button variant="ghost" size="sm" onClick={onCancel}>
            <ArrowLeft className="size-3.5" />
            Retour
          </Button>
        }
      />

      <form onSubmit={handleSubmit} className="pt-6 space-y-4">
        {/* Section : capture & analyse */}
        <Panel className="p-6 space-y-5">
          <div>
            <label className="block text-xs font-medium uppercase tracking-wider text-text-faint">
              URL du site
            </label>
            <div className="mt-2 flex flex-col sm:flex-row gap-2">
              <input
                type="url"
                value={urlDraft}
                onChange={(e) => setUrlDraft(e.target.value)}
                placeholder="https://exemple.fr"
                className="flex-1 h-10 px-3 bg-surface border border-border rounded-md text-sm focus:border-accent focus:outline-none"
              />
              <Button
                type="button"
                variant="primary"
                size="md"
                onClick={runAnalyse}
                disabled={analysing}
              >
                {analysing ? (
                  <Loader2 className="size-3.5 animate-spin" />
                ) : (
                  <Wand2 className="size-3.5" />
                )}
                {analysing ? "Analyse en cours…" : "Analyser le site"}
              </Button>
            </div>
            <p className="mt-2 text-xs text-text-faint">
              Captures d'écran via WordPress mShots, description scrappée depuis les meta du site.
              Tout est ensuite éditable.
            </p>
          </div>

          {(error || info) && (
            <div
              className={`px-4 py-3 rounded-md border text-sm ${
                error
                  ? "border-danger/30 bg-danger/[0.06] text-danger"
                  : "border-warning/30 bg-warning/[0.06] text-warning"
              }`}
            >
              {error ?? info}
            </div>
          )}

          {/* Aperçus screenshots */}
          <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
            <ScreenshotPreview
              variant="desktop"
              path={data.desktopScreenshot}
              loading={recapture.desktop}
              onRecapture={() => runRecapture("desktop")}
              onUpload={(file) => runUpload("desktop", file)}
            />
            <ScreenshotPreview
              variant="mobile"
              path={data.mobileScreenshot}
              loading={recapture.mobile}
              onRecapture={() => runRecapture("mobile")}
              onUpload={(file) => runUpload("mobile", file)}
            />
          </div>
        </Panel>

        {/* Section : PageSpeed Insights */}
        <Panel className="p-6 space-y-5">
          <div className="flex items-start justify-between gap-4 flex-wrap">
            <div>
              <h3 className="text-sm font-semibold text-text inline-flex items-center gap-2">
                <Gauge className="size-4 text-accent" />
                PageSpeed Insights
              </h3>
              <p className="mt-0.5 text-xs text-text-dim">
                Scores Lighthouse mobile et desktop. Optionnels, affichés sur la page détail
                si renseignés.
              </p>
            </div>
            <Button
              type="button"
              variant="outline"
              size="sm"
              onClick={runFetchPageSpeed}
              disabled={pagespeedFetching}
            >
              {pagespeedFetching ? (
                <Loader2 className="size-3.5 animate-spin" />
              ) : (
                <Wand2 className="size-3.5" />
              )}
              {pagespeedFetching ? "Mesure en cours (1 à 2 min)…" : "Récupérer auto"}
            </Button>
          </div>

          <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
            <PageSpeedColumn
              strategy="mobile"
              label="Mobile"
              scores={data.pagespeed?.mobile}
              onChange={(key, value) => patchPageSpeedScore("mobile", key, value)}
              onClear={() => patchPageSpeed("mobile", undefined)}
            />
            <PageSpeedColumn
              strategy="desktop"
              label="Desktop"
              scores={data.pagespeed?.desktop}
              onChange={(key, value) => patchPageSpeedScore("desktop", key, value)}
              onClear={() => patchPageSpeed("desktop", undefined)}
            />
          </div>

          {data.pagespeed?.fetchedAt && (
            <p className="text-micro text-text-faint">
              Dernière mesure auto :{" "}
              {new Date(data.pagespeed.fetchedAt).toLocaleString("fr-FR")}
            </p>
          )}
        </Panel>

        {/* Section : présentation publique */}
        <Panel className="p-6 space-y-5">
          <div className="flex items-start justify-between gap-4 flex-wrap">
            <div>
              <h3 className="text-sm font-semibold text-text">Présentation publique</h3>
              <p className="mt-0.5 text-xs text-text-dim">
                Ce qui apparaîtra sur la page Réalisations et la page détail du projet.
              </p>
            </div>
            <Button
              type="button"
              variant="outline"
              size="sm"
              onClick={runGenerate}
              disabled={generating}
              title="Génère tagline, brief, livrables et highlights via Claude. Ne remplit que les champs vides."
            >
              {generating ? (
                <Loader2 className="size-3.5 animate-spin" />
              ) : (
                <Sparkles className="size-3.5" />
              )}
              {generating ? "Génération…" : "Compléter avec Claude"}
            </Button>
          </div>

          <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
            <Field
              label="Slug (URL)"
              hint="lettres, chiffres et tirets"
              value={data.slug}
              onChange={(v) => patch("slug", v.toLowerCase().replace(/[^a-z0-9-]/g, "-"))}
              placeholder="mon-kit-electrique"
              required
            />
            <Field
              label="Année"
              type="number"
              value={String(data.year)}
              onChange={(v) => patch("year", Number(v) || new Date().getFullYear())}
            />
            <SelectField
              label="Type de projet"
              value={data.type}
              onChange={(v) => patch("type", v as Realisation["type"])}
              options={PROJECT_TYPES.map((t) => ({ value: t, label: TYPE_LABELS[t] }))}
            />
          </div>

          <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
            <Field
              label="Nom du projet"
              value={data.name}
              onChange={(v) => patch("name", v)}
              placeholder="Mon Kit Électrique"
              required
            />
            <Field
              label="Domaine affiché"
              value={data.domain}
              onChange={(v) => patch("domain", v)}
              placeholder="monkitelectrique.fr"
              required
            />
          </div>

          <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
            <Field
              label="Secteur"
              value={data.sector}
              onChange={(v) => patch("sector", v)}
              placeholder="Mobilité électrique"
            />
            <Field
              label="Contexte"
              hint="Affiché en sous-titre"
              value={data.context}
              onChange={(v) => patch("context", v)}
              placeholder="France · B2B"
            />
          </div>

          <TextareaField
            label="Phrase d'accroche"
            hint="Une ligne, mise en italique sur la page détail"
            rows={2}
            value={data.tagline}
            onChange={(v) => patch("tagline", v)}
            placeholder="Convertir les vélos en électrique, en s'appuyant sur un réseau d'ateliers."
            required
          />

          <TextareaField
            label="Résumé"
            hint="Affiché sur la card de la grille (1 ou 2 phrases)"
            rows={3}
            value={data.summary}
            onChange={(v) => patch("summary", v)}
            required
          />

          <TextareaField
            label="Le projet"
            hint="Paragraphe complet pour la page détail"
            rows={6}
            value={data.brief}
            onChange={(v) => patch("brief", v)}
          />

          <TextareaField
            label="Ce qu'on a livré"
            hint="Une ligne par bullet point"
            rows={6}
            value={data.delivered.join("\n")}
            onChange={(v) => patch("delivered", v.split(/\r?\n/))}
            placeholder={"Site vitrine multi-pages...\nOutil de vérification...\nReferencement local..."}
          />

          <HighlightsEditor
            highlights={data.highlights}
            onChange={(h) => patch("highlights", h)}
          />
        </Panel>

        {error && !analysing && !saving && (
          <div className="px-4 py-3 rounded-md border border-danger/30 bg-danger/[0.06] text-danger text-sm">
            {error}
          </div>
        )}

        <div className="flex items-center justify-end gap-2">
          <Button type="button" variant="ghost" size="md" onClick={onCancel}>
            <X className="size-3.5" />
            Annuler
          </Button>
          <Button type="submit" variant="primary" size="md" disabled={saving}>
            {saving ? (
              <Loader2 className="size-3.5 animate-spin" />
            ) : (
              <Save className="size-3.5" />
            )}
            {saving ? "Enregistrement…" : "Enregistrer"}
          </Button>
        </div>
      </form>
    </>
  );
}

// ---------------- form atoms ----------------

function Field({
  label,
  hint,
  value,
  onChange,
  type = "text",
  placeholder,
  required,
}: {
  label: string;
  hint?: string;
  value: string;
  onChange: (v: string) => void;
  type?: string;
  placeholder?: string;
  required?: boolean;
}) {
  return (
    <label className="block">
      <span className="block text-xs font-medium uppercase tracking-wider text-text-faint">
        {label}
        {required && <span className="text-accent ml-1">*</span>}
      </span>
      <input
        type={type}
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        required={required}
        className="mt-1.5 w-full h-10 px-3 bg-surface border border-border rounded-md text-sm focus:border-accent focus:outline-none"
      />
      {hint && <span className="mt-1 block text-micro text-text-faint">{hint}</span>}
    </label>
  );
}

function TextareaField({
  label,
  hint,
  value,
  onChange,
  rows = 3,
  placeholder,
  required,
}: {
  label: string;
  hint?: string;
  value: string;
  onChange: (v: string) => void;
  rows?: number;
  placeholder?: string;
  required?: boolean;
}) {
  return (
    <label className="block">
      <span className="block text-xs font-medium uppercase tracking-wider text-text-faint">
        {label}
        {required && <span className="text-accent ml-1">*</span>}
      </span>
      <textarea
        value={value}
        onChange={(e) => onChange(e.target.value)}
        rows={rows}
        placeholder={placeholder}
        required={required}
        className="mt-1.5 w-full px-3 py-2.5 bg-surface border border-border rounded-md text-sm leading-relaxed focus:border-accent focus:outline-none resize-y"
      />
      {hint && <span className="mt-1 block text-micro text-text-faint">{hint}</span>}
    </label>
  );
}

function SelectField({
  label,
  value,
  onChange,
  options,
}: {
  label: string;
  value: string;
  onChange: (v: string) => void;
  options: { value: string; label: string }[];
}) {
  return (
    <label className="block">
      <span className="block text-xs font-medium uppercase tracking-wider text-text-faint">{label}</span>
      <select
        value={value}
        onChange={(e) => onChange(e.target.value)}
        className="mt-1.5 w-full h-10 px-3 bg-surface border border-border rounded-md text-sm focus:border-accent focus:outline-none"
      >
        {options.map((o) => (
          <option key={o.value} value={o.value}>
            {o.label}
          </option>
        ))}
      </select>
    </label>
  );
}

function HighlightsEditor({
  highlights,
  onChange,
}: {
  highlights: { label: string; value: string }[];
  onChange: (h: { label: string; value: string }[]) => void;
}) {
  const max = 3;

  function update(i: number, patch: Partial<{ label: string; value: string }>) {
    onChange(highlights.map((h, idx) => (idx === i ? { ...h, ...patch } : h)));
  }
  function add() {
    if (highlights.length >= max) return;
    onChange([...highlights, { label: "", value: "" }]);
  }
  function remove(i: number) {
    onChange(highlights.filter((_, idx) => idx !== i));
  }

  return (
    <div>
      <div className="flex items-center justify-between">
        <span className="block text-xs font-medium uppercase tracking-wider text-text-faint">
          Trois chiffres ou faits marquants
        </span>
        <span className="text-micro text-text-faint">{highlights.length} / {max}</span>
      </div>
      <p className="mt-1 text-micro text-text-faint">
        Affichés en bas de la page détail. Du factuel, pas de promesse.
      </p>

      <div className="mt-3 space-y-2">
        {highlights.map((h, i) => (
          <div key={i} className="flex flex-col sm:flex-row gap-2">
            <input
              type="text"
              value={h.label}
              onChange={(e) => update(i, { label: e.target.value })}
              placeholder="Libellé (ex. Modèles vélos)"
              className="sm:w-1/3 h-10 px-3 bg-surface border border-border rounded-md text-sm focus:border-accent focus:outline-none"
            />
            <input
              type="text"
              value={h.value}
              onChange={(e) => update(i, { value: e.target.value })}
              placeholder="Valeur (ex. 750+)"
              className="flex-1 h-10 px-3 bg-surface border border-border rounded-md text-sm focus:border-accent focus:outline-none"
            />
            <button
              type="button"
              onClick={() => remove(i)}
              className="h-10 px-3 inline-flex items-center justify-center rounded-md border border-border text-text-faint hover:text-danger hover:border-danger/40 transition-colors"
              aria-label="Retirer"
            >
              <Trash2 className="size-3.5" />
            </button>
          </div>
        ))}
        {highlights.length < max && (
          <button
            type="button"
            onClick={add}
            className="inline-flex items-center gap-1.5 text-xs text-text-muted hover:text-accent transition-colors"
          >
            <Plus className="size-3" />
            Ajouter un fait
          </button>
        )}
      </div>
    </div>
  );
}

function ScreenshotPreview({
  variant,
  path,
  loading,
  onRecapture,
  onUpload,
}: {
  variant: "desktop" | "mobile";
  path: string | undefined;
  loading: boolean;
  onRecapture: () => void;
  onUpload: (file: File) => void;
}) {
  const isDesktop = variant === "desktop";
  const label = isDesktop ? "Capture desktop" : "Capture mobile";
  const aspect = isDesktop ? "aspect-[16/10]" : "aspect-[9/19] max-w-[180px] mx-auto";
  const fileRef = useRef<HTMLInputElement>(null);

  function handleFile(e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0];
    if (file) onUpload(file);
    e.target.value = "";
  }

  return (
    <div className={isDesktop ? "md:col-span-2" : ""}>
      <div className="flex items-center justify-between mb-2 gap-2">
        <span className="text-xxs uppercase tracking-wider text-text-faint">{label}</span>
        <div className="flex items-center gap-3">
          <button
            type="button"
            onClick={onRecapture}
            disabled={loading}
            className="inline-flex items-center gap-1 text-xxs text-text-muted hover:text-accent transition-colors disabled:opacity-50"
          >
            {loading ? <Loader2 className="size-3 animate-spin" /> : <Camera className="size-3" />}
            {loading ? "En cours…" : "Re-capturer"}
          </button>
          <button
            type="button"
            onClick={() => fileRef.current?.click()}
            disabled={loading}
            className="inline-flex items-center gap-1 text-xxs text-text-muted hover:text-accent transition-colors disabled:opacity-50"
          >
            <Upload className="size-3" />
            Téléverser
          </button>
        </div>
      </div>
      <input
        ref={fileRef}
        type="file"
        accept="image/jpeg,image/png,image/webp"
        onChange={handleFile}
        className="hidden"
      />
      <div
        className={`relative ${aspect} rounded-md border border-border bg-surface-2 overflow-hidden`}
      >
        {path ? (
          <Image
            src={path}
            alt={label}
            fill
            unoptimized
            sizes="(min-width: 1024px) 33vw, 100vw"
            className="object-cover object-top"
          />
        ) : (
          <div className="absolute inset-0 flex flex-col items-center justify-center text-text-faint text-xs gap-1">
            <Camera className="size-4 text-text-dim" />
            <span>Aucune capture</span>
          </div>
        )}
      </div>
      <p className="mt-1.5 text-micro text-text-faint">
        Si la capture auto n'est pas représentative (mobile mal rendu, contenu manquant), utilisez Téléverser.
      </p>
    </div>
  );
}

function PageSpeedColumn({
  label,
  scores,
  onChange,
  onClear,
}: {
  strategy: "mobile" | "desktop";
  label: string;
  scores: LighthouseScores | undefined;
  onChange: (key: keyof LighthouseScores, value: number) => void;
  onClear: () => void;
}) {
  return (
    <div className="rounded-md border border-border bg-stone-900/[0.02] p-4">
      <div className="flex items-center justify-between mb-3">
        <span className="text-xxs uppercase tracking-wider text-text-faint">{label}</span>
        {scores && (
          <button
            type="button"
            onClick={onClear}
            className="text-micro text-text-faint hover:text-danger transition-colors"
          >
            Effacer
          </button>
        )}
      </div>
      <div className="grid grid-cols-2 gap-2">
        {LIGHTHOUSE_LABELS.map(({ key, label: lbl }) => (
          <label key={key} className="block">
            <span className="block text-micro text-text-dim">{lbl}</span>
            <input
              type="number"
              min={0}
              max={100}
              value={scores?.[key] ?? ""}
              onChange={(e) => {
                const raw = e.target.value;
                if (raw === "") {
                  onChange(key, 0);
                  return;
                }
                const n = Math.max(0, Math.min(100, Number(raw)));
                if (Number.isFinite(n)) onChange(key, n);
              }}
              placeholder="0"
              className="mt-1 w-full h-9 px-2 bg-surface border border-border rounded-md text-sm tabular-nums focus:border-accent focus:outline-none"
            />
          </label>
        ))}
      </div>
    </div>
  );
}

function stripCacheBust(p: string | undefined): string | undefined {
  if (!p) return p;
  return p.split("?")[0];
}
