'use client';

import { useMemo, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { AlertTriangle, ArrowLeft, ArrowRight, CheckCircle2, Loader2 } from 'lucide-react';
import { toast } from 'sonner';

import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Textarea } from '@/components/ui/textarea';
import { WarningCallout } from '@/components/ui/warning-callout';
import { apiFetch } from '@/lib/api/client';
import { toastError } from '@/lib/api/toast-error';

interface PreflightItem {
  clientId: string;
  fullName: string;
  stakeLevel: 'low' | 'high';
  highStakesStage: string | null;
  blockers: string[];
  summary: { berths: number; yachts: number; tenancies: number; signedDocs: number };
}

interface Props {
  open: boolean;
  onOpenChange: (next: boolean) => void;
  clientIds: string[];
  onSuccess?: () => void;
}

type Stage = 'preflight' | 'reasons' | 'confirm';

export function BulkArchiveWizard(props: Props) {
  // Key-based remount: body keyed on open + clientIds so its useState
  // initializers re-run each time the wizard opens fresh. Replaces the
  // useEffect(setState, [open]) reset the Compiler flagged.
  return (
    <BulkArchiveWizardBody
      key={props.open ? `open:${props.clientIds.join(',')}` : 'closed'}
      {...props}
    />
  );
}

function BulkArchiveWizardBody({ open, onOpenChange, clientIds, onSuccess }: Props) {
  const qc = useQueryClient();
  const [stage, setStage] = useState<Stage>('preflight');
  const [reasons, setReasons] = useState<Record<string, string>>({});
  const [carouselIndex, setCarouselIndex] = useState(0);

  const preflight = useQuery({
    queryKey: ['bulk-archive-preflight', clientIds.join(',')],
    queryFn: () =>
      apiFetch<{ data: PreflightItem[] }>('/api/v1/clients/bulk-archive-preflight', {
        method: 'POST',
        body: { ids: clientIds },
      }).then((r) => r.data),
    enabled: open && clientIds.length > 0,
  });

  const items = preflight.data ?? [];
  const blocked = useMemo(() => items.filter((i) => i.blockers.length > 0), [items]);
  const highStakes = useMemo(
    () => items.filter((i) => i.stakeLevel === 'high' && i.blockers.length === 0),
    [items],
  );
  const lowStakes = useMemo(
    () => items.filter((i) => i.stakeLevel === 'low' && i.blockers.length === 0),
    [items],
  );
  const archivable = useMemo(() => [...lowStakes, ...highStakes], [lowStakes, highStakes]);

  const allHighStakesReasoned = useMemo(
    () => highStakes.every((i) => (reasons[i.clientId]?.trim().length ?? 0) >= 5),
    [highStakes, reasons],
  );

  const archiveMutation = useMutation({
    mutationFn: () =>
      apiFetch<{ data: { summary: { total: number; succeeded: number; failed: number } } }>(
        '/api/v1/clients/bulk',
        {
          method: 'POST',
          body: {
            action: 'archive',
            ids: archivable.map((i) => i.clientId),
            reasonsByClientId: reasons,
          },
        },
      ),
    onSuccess: (res) => {
      const s = res.data.summary;
      if (s.failed === 0) {
        toast.success(`${s.succeeded} client${s.succeeded === 1 ? '' : 's'} archived.`);
      } else {
        toast.warning(`${s.succeeded} of ${s.total} archived. ${s.failed} failed.`);
      }
      qc.invalidateQueries({ queryKey: ['clients'] });
      onOpenChange(false);
      onSuccess?.();
    },
    onError: (err: unknown) => {
      toastError(err, 'Bulk archive failed');
    },
  });

  const currentHighStakes = highStakes[carouselIndex];

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="sm:max-w-2xl">
        <DialogHeader>
          <DialogTitle>Bulk archive · {clientIds.length} clients</DialogTitle>
          <DialogDescription>
            Smart archive runs the same backend per client. Late-stage deals require an individual
            reason; everything else auto-archives with safe defaults.
          </DialogDescription>
        </DialogHeader>

        {preflight.isLoading ? (
          <div className="py-8 text-center text-sm text-muted-foreground">
            <Loader2 className="h-5 w-5 animate-spin mx-auto mb-2" aria-hidden />
            Checking each client…
          </div>
        ) : preflight.error ? (
          <div className="py-8 text-center text-sm text-red-600">
            Preflight failed:{' '}
            {preflight.error instanceof Error ? preflight.error.message : 'unknown error'}
          </div>
        ) : (
          <>
            {stage === 'preflight' && (
              <div className="space-y-3 max-h-[60vh] overflow-y-auto pr-1">
                <div className="grid grid-cols-3 gap-2 text-sm">
                  <div className="rounded-md border bg-emerald-50 border-emerald-200 p-3">
                    <div className="text-2xl font-bold text-emerald-900">{lowStakes.length}</div>
                    <div className="text-xs text-emerald-800">Auto-archive</div>
                  </div>
                  <div className="rounded-md border bg-amber-50 border-amber-200 p-3">
                    <div className="text-2xl font-bold text-amber-900">{highStakes.length}</div>
                    <div className="text-xs text-amber-800">Need reason</div>
                  </div>
                  <div className="rounded-md border bg-red-50 border-red-200 p-3">
                    <div className="text-2xl font-bold text-red-900">{blocked.length}</div>
                    <div className="text-xs text-red-800">Blocked, will skip</div>
                  </div>
                </div>

                {blocked.length > 0 && (
                  <div className="rounded-md border border-red-300 bg-red-50 p-3 text-xs text-red-900 space-y-1">
                    <div className="font-medium flex items-center gap-1.5">
                      <AlertTriangle className="h-4 w-4" aria-hidden /> Blocked
                    </div>
                    {blocked.slice(0, 5).map((b) => (
                      <div key={b.clientId}>
                        <span className="font-medium">{b.fullName}</span>: {b.blockers[0]}
                      </div>
                    ))}
                    {blocked.length > 5 && <div>…and {blocked.length - 5} more</div>}
                  </div>
                )}

                <div className="rounded-md border bg-muted/30 p-3 text-xs text-muted-foreground">
                  Low-stakes defaults: release available/under-offer berths, keep sold ones, cancel
                  tenancies, leave invoices/signing requests alone. Yachts stay on the archived
                  client. To customise per-client, archive that client individually instead.
                </div>
              </div>
            )}

            {stage === 'reasons' && currentHighStakes && (
              <div className="space-y-3">
                <div className="flex items-center justify-between text-xs text-muted-foreground">
                  <span>
                    Reason {carouselIndex + 1} of {highStakes.length}
                  </span>
                  <span className="flex items-center gap-1">
                    {highStakes.map((_, idx) => (
                      <span
                        key={idx}
                        className={`h-1.5 w-6 rounded-full ${
                          idx === carouselIndex
                            ? 'bg-amber-500'
                            : idx < carouselIndex ||
                                (reasons[highStakes[idx]?.clientId ?? '']?.trim().length ?? 0) >= 5
                              ? 'bg-amber-300'
                              : 'bg-muted'
                        }`}
                      />
                    ))}
                  </span>
                </div>
                <WarningCallout
                  title={
                    <span className="flex items-center gap-2">
                      <span>{currentHighStakes.fullName}</span>
                      <Badge variant="secondary" className="text-xs">
                        {currentHighStakes.highStakesStage}
                      </Badge>
                    </span>
                  }
                >
                  <span className="text-xs">
                    {currentHighStakes.summary.berths > 0
                      ? `${currentHighStakes.summary.berths} berth(s), `
                      : ''}
                    {currentHighStakes.summary.signedDocs > 0
                      ? `${currentHighStakes.summary.signedDocs} signed doc(s), `
                      : ''}
                    {currentHighStakes.summary.tenancies > 0
                      ? `${currentHighStakes.summary.tenancies} tenancy(ies)`
                      : ''}
                  </span>
                </WarningCallout>
                <Textarea
                  value={reasons[currentHighStakes.clientId] ?? ''}
                  onChange={(e) =>
                    setReasons((prev) => ({
                      ...prev,
                      [currentHighStakes.clientId]: e.target.value,
                    }))
                  }
                  placeholder="Why are you archiving this late-stage interest? (≥ 5 chars)"
                  rows={3}
                />
              </div>
            )}

            {stage === 'confirm' && (
              <div className="space-y-2 text-sm">
                <div className="rounded-md border border-emerald-300 bg-emerald-50 p-3 text-emerald-900 flex items-start gap-2">
                  <CheckCircle2 className="h-4 w-4 mt-0.5" aria-hidden />
                  <div>
                    Ready to archive <strong>{archivable.length}</strong> client
                    {archivable.length === 1 ? '' : 's'}
                    {blocked.length > 0 && ` (skipping ${blocked.length} blocked)`}.
                  </div>
                </div>
                <p className="text-xs text-muted-foreground">
                  This action is reversible - restore individually from each archived client.
                </p>
              </div>
            )}
          </>
        )}

        <DialogFooter className="gap-2">
          <Button variant="outline" onClick={() => onOpenChange(false)}>
            Cancel
          </Button>

          {stage === 'preflight' && (
            <Button
              disabled={archivable.length === 0 || preflight.isLoading}
              onClick={() => {
                if (highStakes.length > 0) {
                  setCarouselIndex(0);
                  setStage('reasons');
                } else {
                  setStage('confirm');
                }
              }}
            >
              Continue <ArrowRight className="h-4 w-4 ml-1" aria-hidden />
            </Button>
          )}

          {stage === 'reasons' && (
            <>
              <Button
                variant="outline"
                disabled={carouselIndex === 0}
                onClick={() => setCarouselIndex((i) => Math.max(0, i - 1))}
              >
                <ArrowLeft className="h-4 w-4 mr-1" aria-hidden /> Back
              </Button>
              {carouselIndex < highStakes.length - 1 ? (
                <Button
                  disabled={(reasons[currentHighStakes?.clientId ?? '']?.trim().length ?? 0) < 5}
                  onClick={() => setCarouselIndex((i) => i + 1)}
                >
                  Next <ArrowRight className="h-4 w-4 ml-1" aria-hidden />
                </Button>
              ) : (
                <Button disabled={!allHighStakesReasoned} onClick={() => setStage('confirm')}>
                  Review <ArrowRight className="h-4 w-4 ml-1" aria-hidden />
                </Button>
              )}
            </>
          )}

          {stage === 'confirm' && (
            <Button
              variant="destructive"
              disabled={archiveMutation.isPending}
              onClick={() => archiveMutation.mutate()}
            >
              {archiveMutation.isPending ? (
                <>
                  <Loader2 className="h-4 w-4 animate-spin mr-1.5" aria-hidden /> Archiving…
                </>
              ) : (
                `Archive ${archivable.length}`
              )}
            </Button>
          )}
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
