"use client";

// Inline CF order flow for the V2 panel — replaces the deep-link to
// /parcel-sync. Marius rejected the gis-api shared-pool model
// ([[architools-cutover-state-2026-05-19]]), so this stays on the
// legacy `/api/ancpi/order` route which uses HIS connected ePay
// session and decrements his own credit balance.
//
// State machine:
//   loading-status   → checking ePay session + credit count
//   not-connected    → user must connect ePay first (deep-link out)
//   no-credits       → 0 credits, nothing to do
//   ready            → confirmation step ("1 credit, mai ai X")
//   placing          → POST /api/ancpi/order
//   processing       → poll /api/ancpi/orders for completion
//   done             → final state, optional download link
//   error            → any failure with retry option

import { useCallback, useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import {
  X, Loader2, Check, AlertCircle, FileText, Coins,
  Plug, ArrowRight, Download,
} from "lucide-react";
import { cn } from "@/shared/lib/utils";

type Phase =
  | "loading-status"
  | "connecting"
  | "need-credentials"
  | "no-credits"
  | "ready"
  | "placing"
  | "processing"
  | "done"
  | "error";

interface SessionStatus {
  connected: boolean;
  credits?: number | null;
}

interface OrderListResponse {
  total?: number;
  orders?: Array<{
    id: string;
    nrCadastral: string;
    status: string;
    epayStatus?: string | null;
    documentName?: string | null;
    minioPath?: string | null;
    completedAt?: string | null;
  }>;
}

interface Props {
  open: boolean;
  cadastralRef: string;
  siruta: string;
  /** Optional — passed through to the order body. The legacy route
   * tolerates blanks when judet/uat ids default to 0. */
  judetName?: string;
  uatName?: string;
  onClose: () => void;
}

const POLL_INTERVAL_MS = 3_000;
// ANCPI orders regularly take 60-180s end-to-end (depends on cart load
// + ANCPI document queue); a 90s timeout was firing before the order
// finished even when the queue completed correctly. 180s catches the
// long tail without giving the user a "stuck forever" feel.
const POLL_TIMEOUT_MS = 180_000;

export function CfOrderModal({
  open,
  cadastralRef,
  siruta,
  judetName,
  uatName,
  onClose,
}: Props) {
  const [phase, setPhase] = useState<Phase>("loading-status");
  const [status, setStatus] = useState<SessionStatus | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [orderId, setOrderId] = useState<string | null>(null);
  const [documentUrl, setDocumentUrl] = useState<string | null>(null);
  const [elapsed, setElapsed] = useState(0);
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  const startedAtRef = useRef<number>(0);
  const pollAbortRef = useRef<AbortController | null>(null);

  // Reset state on open
  useEffect(() => {
    if (!open) return;
    setPhase("loading-status");
    setStatus(null);
    setError(null);
    setOrderId(null);
    setDocumentUrl(null);
    setElapsed(0);
    void loadStatus();
    return () => {
      pollAbortRef.current?.abort();
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, cadastralRef, siruta]);

  // Elapsed timer during processing
  useEffect(() => {
    if (phase !== "processing" && phase !== "placing") return;
    const id = setInterval(() => {
      if (startedAtRef.current) {
        setElapsed(Math.round((Date.now() - startedAtRef.current) / 1000));
      }
    }, 500);
    return () => clearInterval(id);
  }, [phase]);

  const evaluateStatus = useCallback((data: SessionStatus) => {
    setStatus(data);
    if (!data.connected) return "need-connect" as const;
    if (data.credits != null && data.credits < 1) {
      setPhase("no-credits");
      return "no-credits" as const;
    }
    setPhase("ready");
    return "ready" as const;
  }, []);

  const tryAutoConnect = useCallback(
    async (creds?: { username: string; password: string }) => {
      setPhase("connecting");
      setError(null);
      try {
        const res = await fetch("/api/ancpi/session", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(creds ?? {}),
        });
        const data = (await res.json()) as {
          success?: boolean;
          credits?: number | null;
          error?: string;
        };
        if (!res.ok || data.error) {
          // 400 with empty body = no server-side env creds. Show the
          // inline credential form. 401 = bad credentials.
          if (creds) {
            setError(data.error ?? "Credențiale ePay invalide");
          }
          setPhase("need-credentials");
          return;
        }
        // Re-fetch status to confirm
        const sRes = await fetch("/api/ancpi/session", { cache: "no-store" });
        const sData = (await sRes.json()) as SessionStatus;
        evaluateStatus(sData);
      } catch {
        setPhase("need-credentials");
        setError("Nu s-a putut conecta automat. Introdu credențialele manual.");
      }
    },
    [evaluateStatus],
  );

  const loadStatus = useCallback(async () => {
    try {
      const res = await fetch("/api/ancpi/session", { cache: "no-store" });
      const data = (await res.json()) as SessionStatus;
      const result = evaluateStatus(data);
      if (result === "need-connect") {
        // Session not active yet — silently try the server-side env
        // credentials (ANCPI_USERNAME / ANCPI_PASSWORD). Most installs
        // have these in Infisical so connection happens transparently.
        await tryAutoConnect();
      }
    } catch {
      setError("Nu pot verifica sesiunea ePay.");
      setPhase("error");
    }
  }, [evaluateStatus, tryAutoConnect]);

  const placeOrder = useCallback(async () => {
    setPhase("placing");
    setError(null);
    startedAtRef.current = Date.now();

    try {
      const res = await fetch("/api/ancpi/order", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          parcels: [
            {
              nrCadastral: cadastralRef,
              nrCF: null,
              siruta,
              judetIndex: 0,
              judetName: judetName ?? "",
              uatId: 0,
              uatName: uatName ?? "",
            },
          ],
        }),
      });
      const data = (await res.json()) as {
        orders?: Array<{ id: string; nrCadastral: string; status: string }>;
        error?: string;
      };
      if (!res.ok || data.error) {
        setError(data.error ?? "Eroare la plasarea comenzii");
        setPhase("error");
        return;
      }
      const placed = (data.orders ?? [])[0];
      if (!placed) {
        setError("Răspuns invalid de la server");
        setPhase("error");
        return;
      }
      setOrderId(placed.id);
      setPhase("processing");
      void pollUntilDone(placed.id);
    } catch {
      setError("Eroare de rețea");
      setPhase("error");
    }
  }, [cadastralRef, siruta, judetName, uatName]);

  const pollUntilDone = useCallback(
    async (id: string) => {
      pollAbortRef.current?.abort();
      const ctrl = new AbortController();
      pollAbortRef.current = ctrl;

      const startedAt = Date.now();
      while (!ctrl.signal.aborted) {
        if (Date.now() - startedAt > POLL_TIMEOUT_MS) {
          setError(
            "Procesarea durează mai mult decât ne-am așteptat. Comanda e plasată — verifică din nou peste câteva minute.",
          );
          setPhase("error");
          return;
        }
        try {
          const res = await fetch(
            `/api/ancpi/orders?nrCadastral=${encodeURIComponent(cadastralRef)}&limit=5`,
            { signal: ctrl.signal, cache: "no-store" },
          );
          if (res.ok) {
            const data = (await res.json()) as OrderListResponse;
            const row = (data.orders ?? []).find((o) => o.id === id);
            if (row) {
              const s = (row.status || "").toLowerCase();
              if (
                s === "completed" ||
                s === "done" ||
                row.minioPath ||
                row.documentName
              ) {
                setDocumentUrl(`/api/ancpi/download?id=${row.id}`);
                setPhase("done");
                return;
              }
              if (s === "failed" || s === "error") {
                setError("Comanda a eșuat la ANCPI.");
                setPhase("error");
                return;
              }
            }
          }
        } catch {
          if (ctrl.signal.aborted) return;
        }
        await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
      }
    },
    [cadastralRef],
  );

  if (!open) return null;
  // Render via portal so the modal escapes the panel's containing
  // block — the parent V2 panel uses backdrop-blur-md which (per CSS
  // spec) creates a containing block for `fixed` descendants. Without
  // the portal the modal anchors to the panel's top-right corner and
  // gets clipped above the viewport.
  if (typeof document === "undefined") return null;

  return createPortal(
    <div
      role="dialog"
      aria-modal="true"
      className="fixed inset-0 z-[100] flex items-center justify-center bg-black/60 px-4 backdrop-blur-sm animate-in fade-in duration-200"
      onClick={(e) => {
        // dismiss on backdrop click only when not mid-flight
        if (
          e.target === e.currentTarget &&
          phase !== "placing" &&
          phase !== "processing"
        ) {
          onClose();
        }
      }}
    >
      <div className="relative w-full max-w-sm rounded-lg border bg-background shadow-2xl animate-in zoom-in-95 fade-in slide-in-from-bottom-2 duration-200">
        {/* Header */}
        <div className="flex items-start justify-between gap-2 border-b px-4 py-3">
          <div className="min-w-0">
            <h2 className="flex items-center gap-1.5 text-sm font-semibold">
              <FileText className="h-4 w-4" />
              Comandă extras CF
            </h2>
            <p className="mt-0.5 truncate font-mono text-xs text-muted-foreground">
              {cadastralRef}
            </p>
          </div>
          <button
            type="button"
            onClick={onClose}
            disabled={phase === "placing" || phase === "processing"}
            aria-label="Închide"
            className="rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-30"
          >
            <X className="h-4 w-4" />
          </button>
        </div>

        {/* Body */}
        <div className="px-4 py-4">
          {/* Loading session status */}
          {phase === "loading-status" && (
            <div className="flex items-center gap-2 py-2 text-sm text-muted-foreground">
              <Loader2 className="h-4 w-4 animate-spin" />
              <span>Verificare credite ePay…</span>
            </div>
          )}

          {/* Connecting to ePay (auto, env creds) */}
          {phase === "connecting" && (
            <div className="flex items-center gap-2 py-2 text-sm text-muted-foreground">
              <Loader2 className="h-4 w-4 animate-spin" />
              <span>Conectare la ePay ANCPI…</span>
            </div>
          )}

          {/* Need credentials — server didn't have them or auto-connect failed */}
          {phase === "need-credentials" && (
            <div className="space-y-3">
              <div className="flex items-start gap-2 rounded-md border border-amber-500/30 bg-amber-50 p-3 text-xs dark:bg-amber-950/30">
                <Plug className="mt-0.5 h-4 w-4 shrink-0 text-amber-600" />
                <div className="space-y-0.5">
                  <p className="font-medium text-amber-900 dark:text-amber-200">
                    Conectează-te la ePay ANCPI
                  </p>
                  <p className="text-amber-800/80 dark:text-amber-200/80">
                    {error ?? "Introdu credențialele tale ePay pentru a continua."}
                  </p>
                </div>
              </div>
              <form
                className="space-y-2"
                onSubmit={(e) => {
                  e.preventDefault();
                  if (!username || !password) return;
                  void tryAutoConnect({ username, password });
                }}
              >
                <label className="block">
                  <span className="text-[11px] uppercase tracking-wider text-muted-foreground">
                    Utilizator
                  </span>
                  <input
                    type="text"
                    autoComplete="username"
                    value={username}
                    onChange={(e) => setUsername(e.target.value)}
                    className="mt-1 w-full rounded-md border bg-background px-2.5 py-1.5 text-sm outline-none focus:border-primary"
                    placeholder="email@exemplu.ro"
                    required
                  />
                </label>
                <label className="block">
                  <span className="text-[11px] uppercase tracking-wider text-muted-foreground">
                    Parolă
                  </span>
                  <input
                    type="password"
                    autoComplete="current-password"
                    value={password}
                    onChange={(e) => setPassword(e.target.value)}
                    className="mt-1 w-full rounded-md border bg-background px-2.5 py-1.5 text-sm outline-none focus:border-primary"
                    required
                  />
                </label>
                <button
                  type="submit"
                  disabled={!username || !password}
                  className="inline-flex w-full items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 disabled:opacity-50"
                >
                  <Plug className="h-3.5 w-3.5" />
                  Conectează
                </button>
                <p className="pt-1 text-[10px] text-muted-foreground">
                  Credențialele sunt trimise direct la ANCPI; nu sunt
                  păstrate la noi după sfârșitul sesiunii.
                </p>
              </form>
            </div>
          )}

          {/* No credits */}
          {phase === "no-credits" && (
            <div className="space-y-3">
              <div className="flex items-start gap-2 rounded-md border border-destructive/30 bg-destructive/10 p-3 text-sm">
                <Coins className="mt-0.5 h-4 w-4 shrink-0 text-destructive" />
                <div className="space-y-1">
                  <p className="font-medium text-destructive">
                    Credite insuficiente
                  </p>
                  <p className="text-xs text-destructive/80">
                    Ai 0 credite. Reîncarcă-ți contul ePay ANCPI înainte
                    de a comanda.
                  </p>
                </div>
              </div>
            </div>
          )}

          {/* Ready — confirmation */}
          {phase === "ready" && (
            <div className="space-y-3">
              <p className="text-sm">
                Ești pe cale să comanzi un extras de Carte Funciară pentru
                această parcelă.
              </p>
              <div className="flex items-center justify-between rounded-md border bg-muted/40 px-3 py-2.5 text-sm">
                <div className="flex items-center gap-2">
                  <Coins className="h-4 w-4 text-muted-foreground" />
                  <span className="text-muted-foreground">Cost</span>
                </div>
                <span className="font-mono font-semibold">1 credit</span>
              </div>
              <div className="flex items-center justify-between rounded-md border bg-muted/40 px-3 py-2.5 text-sm">
                <div className="flex items-center gap-2">
                  <Coins className="h-4 w-4 text-muted-foreground" />
                  <span className="text-muted-foreground">Sold disponibil</span>
                </div>
                <span className="font-mono font-semibold tabular-nums">
                  {status?.credits ?? "—"} credite
                </span>
              </div>
              <div className="flex items-center justify-between rounded-md border border-emerald-500/30 bg-emerald-50 px-3 py-2.5 text-sm dark:bg-emerald-950/30">
                <span className="text-muted-foreground">După comandă</span>
                <span className="font-mono font-semibold tabular-nums text-emerald-700 dark:text-emerald-300">
                  {status?.credits != null
                    ? `${status.credits - 1} credite`
                    : "—"}
                </span>
              </div>
            </div>
          )}

          {/* Placing or Processing */}
          {(phase === "placing" || phase === "processing") && (
            <div className="space-y-3">
              <StepRow
                done={phase !== "placing"}
                active={phase === "placing"}
                label="Plasare comandă ANCPI"
              />
              <StepRow
                done={false}
                active={phase === "processing"}
                pending={phase === "placing"}
                label={
                  phase === "processing"
                    ? `Procesare la ANCPI… (${elapsed}s)`
                    : "Procesare la ANCPI"
                }
              />
              <StepRow
                done={false}
                active={false}
                pending
                label="Document gata"
              />
              {phase === "processing" && (
                <p className="pt-1 text-[11px] italic text-muted-foreground">
                  Poate dura până la 3 minute. Poți închide fereastra —
                  comanda continuă în fundal.
                </p>
              )}
            </div>
          )}

          {/* Done */}
          {phase === "done" && (
            <div className="space-y-3">
              <div className="flex flex-col items-center gap-2 py-2 text-center animate-in zoom-in-95 duration-300">
                <div className="flex h-12 w-12 items-center justify-center rounded-full bg-emerald-100 dark:bg-emerald-950">
                  <Check className="h-7 w-7 text-emerald-600 animate-in zoom-in-50 duration-500" />
                </div>
                <div>
                  <p className="font-medium">Extras CF gata!</p>
                  <p className="text-xs text-muted-foreground">
                    Documentul a fost generat și descărcat în spațiul tău.
                  </p>
                </div>
              </div>
              {documentUrl && (
                <a
                  href={documentUrl}
                  target="_blank"
                  rel="noopener noreferrer"
                  className="inline-flex w-full items-center justify-center gap-1.5 rounded-md border bg-primary px-3 py-2 text-sm font-medium text-primary-foreground hover:opacity-90"
                >
                  <Download className="h-3.5 w-3.5" />
                  Descarcă PDF
                </a>
              )}
            </div>
          )}

          {/* Error */}
          {phase === "error" && (
            <div className="space-y-3">
              <div className="flex flex-col items-center gap-2 py-2 text-center animate-in zoom-in-95 duration-300">
                <div className="flex h-12 w-12 items-center justify-center rounded-full bg-destructive/10">
                  <AlertCircle className="h-7 w-7 text-destructive" />
                </div>
                <div>
                  <p className="font-medium">Comanda nu a putut fi plasată</p>
                  <p className="text-xs text-muted-foreground">
                    {error ?? "Eroare necunoscută"}
                  </p>
                </div>
              </div>
            </div>
          )}
        </div>

        {/* Footer */}
        <div className="flex items-center justify-end gap-2 border-t bg-muted/30 px-4 py-3">
          {phase === "ready" && (
            <>
              <button
                type="button"
                onClick={onClose}
                className="rounded-md px-3 py-1.5 text-sm font-medium hover:bg-muted"
              >
                Anulează
              </button>
              <button
                type="button"
                onClick={placeOrder}
                className="inline-flex items-center gap-1 rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90"
              >
                Confirmă · 1 credit
                <ArrowRight className="h-3.5 w-3.5" />
              </button>
            </>
          )}
          {(phase === "loading-status" ||
            phase === "connecting" ||
            phase === "no-credits" ||
            phase === "need-credentials") && (
            <button
              type="button"
              onClick={onClose}
              className="rounded-md px-3 py-1.5 text-sm font-medium hover:bg-muted"
            >
              Închide
            </button>
          )}
          {(phase === "placing" || phase === "processing") && (
            <button
              type="button"
              onClick={onClose}
              className="rounded-md px-3 py-1.5 text-sm font-medium hover:bg-muted"
              title="Comanda continuă în fundal"
            >
              Închide fereastra
            </button>
          )}
          {phase === "done" && (
            <button
              type="button"
              onClick={onClose}
              className="rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90"
            >
              Gata
            </button>
          )}
          {phase === "error" && (
            <>
              <button
                type="button"
                onClick={onClose}
                className="rounded-md px-3 py-1.5 text-sm font-medium hover:bg-muted"
              >
                Închide
              </button>
              <button
                type="button"
                onClick={() => void loadStatus()}
                className="inline-flex items-center gap-1 rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90"
              >
                Reîncearcă
              </button>
            </>
          )}
        </div>
      </div>
    </div>,
    document.body,
  );
}

function StepRow({
  done,
  active,
  pending,
  label,
}: {
  done: boolean;
  active: boolean;
  pending?: boolean;
  label: string;
}) {
  return (
    <div
      className={cn(
        "flex items-center gap-2 rounded-md border px-3 py-2 text-sm transition-colors",
        active && "border-primary/30 bg-primary/5",
        done && "border-emerald-500/30 bg-emerald-50 dark:bg-emerald-950/30",
        pending && !active && "opacity-50",
      )}
    >
      <span
        className={cn(
          "flex h-5 w-5 shrink-0 items-center justify-center rounded-full",
          active && "bg-primary text-primary-foreground",
          done && "bg-emerald-500 text-white",
          pending && !active && "bg-muted text-muted-foreground",
        )}
      >
        {done ? (
          <Check className="h-3 w-3 animate-in zoom-in-50 duration-300" />
        ) : active ? (
          <Loader2 className="h-3 w-3 animate-spin" />
        ) : (
          <span className="h-1.5 w-1.5 rounded-full bg-current" />
        )}
      </span>
      <span
        className={cn(
          done && "text-emerald-700 dark:text-emerald-300",
          active && "font-medium",
        )}
      >
        {label}
      </span>
    </div>
  );
}
