// src/components/keywords/seranking-sync-dialog.tsx — dialog de confirmation
// du coût d'un sync SE-Ranking, partagé par les 3 surfaces (réservoir,
// recherche, planning) via le hook `useSerankingSync`. Tue la triplication
// des anciens handlers `syncSeranking` (estimate → ligne solde selon mode →
// confirmer → toast récap) : voir
// docs/superpowers/specs/2026-07-14-seranking-monetization-design.md §UI.
"use client";

import { RefreshCwIcon, ZapIcon } from "lucide-react";
import { useTranslations } from "next-intl";
import { useState, useTransition } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { createSerankingPackCheckoutAction } from "@/lib/billing/pack-actions";
import type { KeywordSelection } from "@/lib/keywords/list-query";
import {
  estimateSerankingSyncAction,
  type SerankingEstimate,
  syncSerankingAction,
} from "@/lib/seranking/actions";
import { cn } from "@/lib/utils";

export function useSerankingSync(
  siteId: string,
  opts: { onDone: () => void },
): {
  /** Ouvre le dialog et lance l'estimation pour cette sélection. */
  open: (selection: KeywordSelection) => void;
  /** À rendre par la surface appelante (un seul Dialog par surface). */
  dialog: React.ReactNode;
  /** True pendant l'appel `syncSerankingAction` (confirmer en cours). */
  syncing: boolean;
} {
  const t = useTranslations("Keywords");
  const tCommon = useTranslations("Common");

  const [open, setOpen] = useState(false);
  const [selection, setSelection] = useState<KeywordSelection | null>(null);
  const [estimate, setEstimate] = useState<SerankingEstimate | null>(null);
  const [estimateError, setEstimateError] = useState<string | null>(null);
  const [estimating, startEstimating] = useTransition();
  const [syncing, startSync] = useTransition();
  const [buyPending, setBuyPending] = useState(false);

  function openDialog(sel: KeywordSelection) {
    setSelection(sel);
    setEstimate(null);
    setEstimateError(null);
    setOpen(true);
    startEstimating(async () => {
      const res = await estimateSerankingSyncAction(siteId, sel);
      if (!res.ok) {
        setEstimateError(res.error);
        return;
      }
      setEstimate(res);
    });
  }

  function closeDialog() {
    setOpen(false);
    setSelection(null);
    setEstimate(null);
    setEstimateError(null);
  }

  async function buyPack() {
    setBuyPending(true);
    try {
      const res = await createSerankingPackCheckoutAction();
      if ("url" in res) {
        window.location.href = res.url;
      } else {
        toast.error(t("buyPackError"));
        setBuyPending(false);
      }
    } catch {
      toast.error(t("buyPackError"));
      setBuyPending(false);
    }
  }

  function confirm() {
    if (!selection) return;
    startSync(async () => {
      try {
        const res = await syncSerankingAction(siteId, selection);
        if (!res.ok) {
          if (res.quota) {
            const current = res.quota.limit - res.quota.remaining;
            toast.error(
              t("quotaExceeded", { current, limit: res.quota.limit }),
            );
          } else {
            toast.error(res.error);
          }
          closeDialog();
          return;
        }
        const parts = [t("recapEnriched", { count: res.enriched })];
        if (res.noData > 0) {
          parts.push(t("recapNoData", { count: res.noData }));
        }
        if (res.skippedCountries.length > 0) {
          parts.push(
            t("recapSkipped", { countries: res.skippedCountries.join(", ") }),
          );
        }
        toast.success(t("recapTitle", { summary: parts.join(" · ") }));
        closeDialog();
        opts.onDone();
      } catch {
        toast.error(t("syncError"));
        closeDialog();
      }
    });
  }

  const insufficientBalance =
    estimate !== null &&
    estimate.access.mode === "metered" &&
    estimate.access.balance < estimate.requests;

  const dialog = (
    <Dialog
      open={open}
      onOpenChange={(next) => {
        if (!next) closeDialog();
      }}
    >
      <DialogContent>
        <DialogHeader>
          <DialogTitle>{t("dialogTitle")}</DialogTitle>
          <DialogDescription>{t("dialogDescription")}</DialogDescription>
        </DialogHeader>

        {estimating ? (
          <div className="flex items-center gap-2 text-muted-foreground text-sm">
            <RefreshCwIcon className="size-4 animate-spin" aria-hidden />
            {tCommon("loading")}
          </div>
        ) : estimateError ? (
          <p className="text-destructive text-sm" role="alert">
            {estimateError}
          </p>
        ) : estimate ? (
          <div className="flex flex-col gap-2 text-sm">
            <p className="font-medium">
              {[
                t("estimateSyncs", { count: estimate.requests }),
                t("estimateKeywords", { count: estimate.keywords }),
                t("estimateCountries", { count: estimate.countries }),
              ].join(" · ")}
            </p>
            {estimate.skippedCountries.length > 0 ? (
              <p className="text-muted-foreground">
                {t("skippedCountries", {
                  countries: estimate.skippedCountries.join(", "),
                })}
              </p>
            ) : null}

            {estimate.access.mode === "unlimited" ? (
              <p className="text-muted-foreground">{t("balanceUnlimited")}</p>
            ) : estimate.access.mode === "byok" ? (
              <p className="text-muted-foreground">{t("balanceByok")}</p>
            ) : (
              <div className="flex flex-wrap items-center justify-between gap-2 rounded-md border bg-muted/40 p-2">
                <span
                  className={cn(
                    "text-muted-foreground",
                    insufficientBalance && "text-destructive",
                  )}
                >
                  {t("balanceMetered", { count: estimate.access.balance })}
                </span>
                {insufficientBalance ? (
                  <Button
                    type="button"
                    size="sm"
                    variant="outline"
                    onClick={buyPack}
                    disabled={buyPending}
                  >
                    <ZapIcon className="size-4" aria-hidden />
                    {buyPending ? tCommon("loading") : t("buyPackCta")}
                  </Button>
                ) : null}
              </div>
            )}
          </div>
        ) : null}

        <DialogFooter>
          <Button
            type="button"
            variant="outline"
            onClick={closeDialog}
            disabled={syncing}
          >
            {tCommon("cancel")}
          </Button>
          <Button
            type="button"
            onClick={confirm}
            disabled={
              estimating ||
              !estimate ||
              syncing ||
              estimateError !== null ||
              insufficientBalance
            }
          >
            {syncing ? tCommon("loading") : t("confirm")}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );

  return { open: openDialog, dialog, syncing };
}
