"use client";

import { useEffect, useState } from "react";
import { toast } from "sonner";
import { AlertTriangle, Loader2, ShieldCheck, Unplug } from "lucide-react";
import { useRepositories } from "@/di/repository-provider";
import { useT } from "@/shared/i18n/client";
import { useApiQuery } from "@/presentation/hooks/use-api-query";
import { useApiMutation } from "@/presentation/hooks/use-api-mutation";
import { Alert, AlertDescription } from "@/presentation/components/ui/alert";
import { Button } from "@/presentation/components/ui/button";
import { Checkbox } from "@/presentation/components/ui/checkbox";
import {
  Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle,
} from "@/presentation/components/ui/dialog";
import { Progress } from "@/presentation/components/ui/progress";
import type { LinkbycarCompanyVerification } from "@/domain/entities/vehicle";

/** 4s x 45 = roughly 3 minutes of watching before we tell the operator to come back later. */
const POLL_INTERVAL_MS = 4000;
const MAX_POLLS = 45;

interface Props {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  /** A companies.id — the same id the vehicles list's company filter uses. */
  companyId: number | null;
  /** Called once work has been queued, so the caller can refresh its list. */
  onQueued?: () => void;
}

/**
 * The body is mounted only while the dialog is open and is keyed by company, so
 * every open starts from fresh state and fresh counts — another operator may
 * have disconnected vehicles since this page was loaded.
 */
export default function CompanyLinkbycarDisconnectDialog({
  open,
  onOpenChange,
  companyId,
  onQueued,
}: Props) {
  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-w-lg">
        {open && (
          <DisconnectBody
            key={companyId ?? "none"}
            companyId={companyId}
            onClose={() => onOpenChange(false)}
            onQueued={onQueued}
          />
        )}
      </DialogContent>
    </Dialog>
  );
}

function DisconnectBody({
  companyId,
  onClose,
  onQueued,
}: {
  companyId: number | null;
  onClose: () => void;
  onQueued?: () => void;
}) {
  const t = useT();
  const container = useRepositories();
  const [includeAll, setIncludeAll] = useState(false);
  const [running, setRunning] = useState(false);
  const [queued, setQueued] = useState(0);
  const [polls, setPolls] = useState(0);
  const [verification, setVerification] = useState<LinkbycarCompanyVerification | null>(null);

  const copy = t.vehicles.companyDisconnect;

  const { data: summary, loading, error, refetch } = useApiQuery(
    () => container.vehicleRepository.getCompanyLinkbycarSummary(companyId as number),
    { deps: [companyId], enabled: companyId !== null }
  );

  const targets = includeAll ? summary?.targets.with_vin ?? 0 : summary?.targets.linked ?? 0;
  const stillLinked = (summary?.connected ?? 0) + (summary?.pending ?? 0);
  const startedFrom = Math.max(queued, 1);
  // A catch-up sweep also touches vehicles already counted as disconnected, so
  // "nothing linked left" does not mean the sweep has finished.
  const done = running && stillLinked === 0 && !includeAll;
  const stalled = running && !done && polls >= MAX_POLLS;

  // While the queue drains, re-read the counts. connected + pending is the only
  // honest progress signal available without a per-batch tracking table. A
  // re-armed timeout rather than an interval, so `polls` stays plain state.
  useEffect(() => {
    if (!running || done || polls >= MAX_POLLS) return;

    const id = setTimeout(() => {
      setPolls((n) => n + 1);
      refetch();
    }, POLL_INTERVAL_MS);

    return () => clearTimeout(id);
  }, [running, done, polls, refetch]);

  const disconnectMutation = useApiMutation(
    (payload: { companyId: number; includeAll: boolean }) =>
      container.vehicleRepository.disconnectCompanyLinkbycar(payload.companyId, payload.includeAll),
    {
      onSuccess: (result) => {
        const count = result?.queued ?? 0;
        if (count === 0) {
          toast.info(copy.nothing);
          return;
        }
        toast.success(copy.queued(count));
        setQueued(count);
        setRunning(true);
        setPolls(0);
        // A verdict taken before the sweep would be read as its result.
        setVerification(null);
        onQueued?.();
      },
    }
  );

  // The only read here that does not just believe our own columns: it pages the
  // provider's listing and cross-references it, so it is slow and on demand.
  const verifyMutation = useApiMutation(
    (id: number) => container.vehicleRepository.verifyCompanyLinkbycar(id),
    {
      // No onError toast: useApiMutation already surfaces the backend message,
      // which for a 503 says LinkByCar itself is unreachable — more useful than
      // generic copy.
      loadingMessage: copy.verify.running,
      onSuccess: (result) => setVerification(result ?? null),
    }
  );

  const staleStillRegistered = (verification?.still_registered ?? []).filter(
    (v) => v.local_status !== "C" && v.local_status !== "P"
  ).length;

  return (
    <>
      <DialogHeader>
        <DialogTitle>{copy.title}</DialogTitle>
        <DialogDescription>{summary ? summary.company.name : copy.loading}</DialogDescription>
      </DialogHeader>

      {companyId === null ? (
        <p className="text-sm text-muted-foreground">{copy.pickCompany}</p>
      ) : running && summary ? (
        // Checked before `loading`: each poll flips the query back to loading and
        // would otherwise replace the progress view with a spinner every 4s.
        <div className="space-y-4 py-2">
          <p className="text-sm font-medium">{copy.progressTitle}</p>
          <Progress value={Math.round(((startedFrom - stillLinked) / startedFrom) * 100)} />
          <p className="text-sm text-muted-foreground">
            {done ? copy.progressDone : copy.progressRemaining(stillLinked)}
          </p>
          {includeAll && <p className="text-xs text-muted-foreground">{copy.progressCatchUp}</p>}
          {stalled && <p className="text-xs text-muted-foreground">{copy.progressStalled}</p>}
        </div>
      ) : loading ? (
        <div className="flex items-center gap-2 py-6 text-sm text-muted-foreground">
          <Loader2 className="w-4 h-4 animate-spin" />
          {copy.loading}
        </div>
      ) : !summary ? (
        <p className="text-sm text-destructive">{error ?? copy.loadError}</p>
      ) : (
        <div className="space-y-4">
          <div className="grid grid-cols-3 gap-2 text-center">
            <Metric label={copy.counts.total} value={summary.vehicles_total} />
            <Metric label={copy.counts.connected} value={summary.connected} />
            <Metric label={copy.counts.pending} value={summary.pending} />
            <Metric label={copy.counts.eligible} value={summary.eligible} />
            <Metric label={copy.counts.notConnected} value={summary.not_connected} />
          </div>

          <Alert variant="destructive">
            <AlertTriangle />
            <AlertDescription>{copy.warning}</AlertDescription>
          </Alert>

          <p className="text-sm">{copy.targetLinked(summary.targets.linked)}</p>

          <label className="flex items-start gap-2 text-sm cursor-pointer">
            <Checkbox
              className="mt-0.5"
              checked={includeAll}
              onCheckedChange={(checked) => setIncludeAll(checked === true)}
            />
            <span>
              {copy.includeAllLabel}
              <span className="block text-xs text-muted-foreground">
                {copy.includeAllHint(summary.targets.with_vin)}
              </span>
            </span>
          </label>

          {targets === 0 && <p className="text-sm text-muted-foreground">{copy.nothing}</p>}
        </div>
      )}

      {/* Available before and after the sweep: before, it shows the real target;
          after, it is the proof that the vehicles are gone from LinkByCar. */}
      {companyId !== null && (
        <div className="space-y-2 border-t pt-3">
          <Button
            variant="outline"
            size="sm"
            disabled={verifyMutation.loading}
            onClick={() => verifyMutation.mutate(companyId)}
          >
            {verifyMutation.loading ? (
              <Loader2 className="w-4 h-4 mr-2 animate-spin" />
            ) : (
              <ShieldCheck className="w-4 h-4 mr-2" />
            )}
            {copy.verify.trigger}
          </Button>

          {verification && (
            <div className="space-y-1">
              {verification.clean ? (
                <p className="text-sm font-medium">{copy.verify.clean}</p>
              ) : (
                <>
                  <p className="text-sm font-medium">
                    {copy.verify.remaining(verification.still_registered_count)}
                  </p>
                  {staleStillRegistered > 0 && (
                    <p className="text-xs text-muted-foreground">
                      {copy.verify.staleHint(staleStillRegistered)}
                    </p>
                  )}
                  <div className="max-h-40 overflow-y-auto rounded-md border divide-y">
                    {verification.still_registered.map((v) => (
                      <div
                        key={v.vehicle_id}
                        className="flex items-center justify-between gap-2 px-2 py-1 text-xs"
                      >
                        <span className="font-mono">
                          {v.numberplate}
                          {v.archived && (
                            <span className="ml-1 text-muted-foreground">
                              ({copy.verify.archived})
                            </span>
                          )}
                        </span>
                        <span className="text-muted-foreground">
                          {v.local_status} → {v.provider_status ?? "?"}
                        </span>
                      </div>
                    ))}
                  </div>
                </>
              )}
              <p className="text-xs text-muted-foreground">
                {copy.verify.checked(verification.checked, verification.provider_total)}
              </p>
              {verification.linked_but_absent_count > 0 && (
                <p className="text-xs text-muted-foreground">
                  {copy.verify.absentHint(verification.linked_but_absent_count)}
                </p>
              )}
            </div>
          )}
        </div>
      )}

      <div className="flex justify-end gap-2 pt-2">
        <Button variant="outline" onClick={onClose}>
          {running ? copy.close : t.common.cancel}
        </Button>
        {!running && (
          <Button
            variant="destructive"
            disabled={companyId === null || !summary || targets === 0 || disconnectMutation.loading}
            onClick={() =>
              companyId !== null && disconnectMutation.mutate({ companyId, includeAll })
            }
          >
            {disconnectMutation.loading ? (
              <Loader2 className="w-4 h-4 mr-2 animate-spin" />
            ) : (
              <Unplug className="w-4 h-4 mr-2" />
            )}
            {copy.confirm}
          </Button>
        )}
      </div>
    </>
  );
}

function Metric({ label, value }: { label: string; value: number }) {
  return (
    <div className="rounded-md border p-2">
      <p className="text-lg font-semibold leading-tight">{value}</p>
      <p className="text-xs text-muted-foreground">{label}</p>
    </div>
  );
}
