'use client';

import { useMemo, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { AlertTriangle, Anchor, FileText, Loader2, Receipt, Ship, Users } 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 { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Textarea } from '@/components/ui/textarea';
import { apiFetch } from '@/lib/api/client';
import { stageLabelFor } from '@/lib/constants';
import { toastError } from '@/lib/api/toast-error';

interface DossierBerth {
  berthId: string;
  mooringNumber: string;
  status: string;
  linkedInterestIds: string[];
  otherInterests: Array<{
    interestId: string;
    clientId: string | null;
    clientName: string | null;
    pipelineStage: string;
    daysSinceUpdate: number;
  }>;
}
interface DossierDocument {
  documentId: string;
  templateName: string | null;
  status: string;
  documensoEnvelopeId: string | null;
  isInFlight: boolean;
}
interface DossierYacht {
  yachtId: string;
  name: string;
  hullNumber: string | null;
  status: string;
}
interface DossierTenancy {
  tenancyId: string;
  berthId: string;
  mooringNumber: string;
  status: string;
  startDate: string;
}
interface DossierInvoice {
  invoiceId: string;
  invoiceNumber: string;
  status: string;
  total: string;
  currency: string;
}
interface DossierInterest {
  interestId: string;
  pipelineStage: string;
  primaryBerthMooring: string | null;
  hasSignedEoi: boolean;
}
interface ArchiveDossier {
  client: { id: string; fullName: string; portId: string; archivedAt: string | null };
  stakeLevel: 'low' | 'high';
  highStakesStage: string | null;
  interests: DossierInterest[];
  berths: DossierBerth[];
  yachts: DossierYacht[];
  companies: Array<{ companyId: string; name: string; membershipRole: string | null }>;
  tenancies: DossierTenancy[];
  invoices: DossierInvoice[];
  documents: DossierDocument[];
  hasPortalUser: boolean;
  blockers: string[];
}

type BerthAction = 'release' | 'retain';
type YachtAction = 'transfer' | 'mark_sold_away' | 'retain';
type TenancyAction = 'cancel' | 'transfer';
type InvoiceAction = 'void' | 'write_off' | 'leave';
type DocumentAction = 'void_documenso' | 'leave';

interface Props {
  open: boolean;
  onOpenChange: (next: boolean) => void;
  clientId: string;
  clientName: string;
  /** Called after successful archive. */
  onSuccess?: () => void;
}

export function SmartArchiveDialog(props: Props) {
  // Key-based remount: body keyed on open + clientId; once the dossier
  // loads, an inner key forces the decision-defaults to seed cleanly.
  return (
    <SmartArchiveDialogShell key={props.open ? `open:${props.clientId}` : 'closed'} {...props} />
  );
}

function SmartArchiveDialogShell({ open, onOpenChange, clientId, clientName, onSuccess }: Props) {
  const qc = useQueryClient();
  const dossierQuery = useQuery({
    queryKey: ['client-archive-dossier', clientId],
    queryFn: () =>
      apiFetch<{ data: ArchiveDossier }>(`/api/v1/clients/${clientId}/archive-dossier`),
    enabled: open,
  });
  const dossier = dossierQuery.data?.data;
  // While the dossier is loading the body's useState initializers can't
  // derive defaults, so we delay-key the body so it mounts ONCE with the
  // right seed when the data arrives. Replaces the prior
  // useEffect(setState, [dossier]) sync that the Compiler flagged.
  return (
    <SmartArchiveDialogBody
      key={dossier ? 'loaded' : 'loading'}
      open={open}
      onOpenChange={onOpenChange}
      clientId={clientId}
      clientName={clientName}
      onSuccess={onSuccess}
      dossier={dossier ?? null}
      isLoading={dossierQuery.isLoading}
      error={dossierQuery.error}
      qc={qc}
    />
  );
}

function SmartArchiveDialogBody({
  open,
  onOpenChange,
  clientId,
  clientName,
  onSuccess,
  dossier,
  isLoading,
  error,
  qc,
}: Props & {
  dossier: ArchiveDossier | null;
  isLoading: boolean;
  error: unknown;
  qc: ReturnType<typeof useQueryClient>;
}) {
  // ─── Local decision state ────────────────────────────────────────────────
  const [reason, setReason] = useState('');
  const [acknowledged, setAcknowledged] = useState(false);
  const [berthDecisions, setBerthDecisions] = useState<Record<string, BerthAction>>(() =>
    dossier
      ? Object.fromEntries(
          dossier.berths.map((berth) => [
            berth.berthId,
            berth.status === 'sold' ? ('retain' as BerthAction) : ('release' as BerthAction),
          ]),
        )
      : {},
  );
  const [yachtDecisions, setYachtDecisions] = useState<Record<string, YachtAction>>(() =>
    dossier
      ? Object.fromEntries(dossier.yachts.map((y) => [y.yachtId, 'retain' as YachtAction]))
      : {},
  );
  const [tenancyDecisions, setTenancyDecisions] = useState<Record<string, TenancyAction>>(() =>
    dossier
      ? Object.fromEntries(dossier.tenancies.map((r) => [r.tenancyId, 'cancel' as TenancyAction]))
      : {},
  );
  const [invoiceDecisions, setInvoiceDecisions] = useState<Record<string, InvoiceAction>>(() =>
    dossier
      ? Object.fromEntries(dossier.invoices.map((i) => [i.invoiceId, 'leave' as InvoiceAction]))
      : {},
  );
  const [documentDecisions, setDocumentDecisions] = useState<Record<string, DocumentAction>>(() =>
    dossier
      ? Object.fromEntries(dossier.documents.map((d) => [d.documentId, 'leave' as DocumentAction]))
      : {},
  );
  const hasSignedDocs = useMemo(
    () =>
      dossier?.documents.some((d) => d.status === 'completed' || d.status === 'signed') ?? false,
    [dossier],
  );

  const canSubmit = useMemo(() => {
    if (!dossier) return false;
    if (dossier.blockers.length > 0) return false;
    if (dossier.stakeLevel === 'high' && reason.trim().length < 5) return false;
    if (hasSignedDocs && !acknowledged) return false;
    return true;
  }, [dossier, reason, hasSignedDocs, acknowledged]);

  const archiveMutation = useMutation({
    mutationFn: () => {
      if (!dossier) throw new Error('No dossier');
      // Pick the first linked interest for this berth from the
      // authoritative dossier join. Berths with no linked interest for
      // this client are skipped - sending an empty interestId would
      // make the server-side delete silently match zero rows.
      const berthDec = dossier.berths
        .map((b) => {
          const interestId = b.linkedInterestIds[0];
          if (!interestId) return null;
          return {
            berthId: b.berthId,
            interestId,
            action: berthDecisions[b.berthId] ?? 'retain',
          };
        })
        .filter(
          (x): x is { berthId: string; interestId: string; action: BerthAction } => x !== null,
        );
      return apiFetch<{ data: { releasedBerths: Array<{ mooringNumber: string }> } }>(
        `/api/v1/clients/${clientId}/archive`,
        {
          method: 'POST',
          body: {
            reason,
            acknowledgedSignedDocuments: acknowledged,
            berthDecisions: berthDec,
            yachtDecisions: dossier.yachts.map((y) => ({
              yachtId: y.yachtId,
              action: yachtDecisions[y.yachtId] ?? 'retain',
            })),
            tenancyDecisions: dossier.tenancies.map((r) => ({
              tenancyId: r.tenancyId,
              action: tenancyDecisions[r.tenancyId] ?? 'cancel',
            })),
            invoiceDecisions: dossier.invoices.map((i) => ({
              invoiceId: i.invoiceId,
              action: invoiceDecisions[i.invoiceId] ?? 'leave',
            })),
            documentDecisions: dossier.documents.map((d) => ({
              documentId: d.documentId,
              action: documentDecisions[d.documentId] ?? 'leave',
            })),
          },
        },
      );
    },
    onSuccess: (res) => {
      const released = res.data.releasedBerths;
      toast.success(
        released.length > 0
          ? `${clientName} archived. ${released.length} berth${released.length === 1 ? '' : 's'} released.`
          : `${clientName} archived.`,
      );
      qc.invalidateQueries({ queryKey: ['clients'] });
      // Invalidate the single-client query AND the dossier so detail
      // pages re-fetch (header now shows Archived badge) and a re-open
      // of the dialog re-fetches a fresh dossier.
      qc.invalidateQueries({ queryKey: ['clients', clientId] });
      qc.removeQueries({ queryKey: ['client-archive-dossier', clientId] });
      qc.invalidateQueries({ queryKey: ['berths'] });
      qc.invalidateQueries({ queryKey: ['interests'] });
      onOpenChange(false);
      onSuccess?.();
    },
    onError: (err: unknown) => {
      toastError(err, 'Archive failed');
    },
  });

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="sm:max-w-2xl">
        <DialogHeader>
          <DialogTitle>Archive {clientName}</DialogTitle>
          <DialogDescription>
            Archive is reversible - the client can be restored from the archived list. Decide what
            should happen to the relationships below before continuing.
          </DialogDescription>
        </DialogHeader>

        {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 />
            Loading dossier…
          </div>
        ) : error || !dossier ? (
          <div className="py-8 text-center text-sm text-red-600">
            Failed to load dossier: {error instanceof Error ? error.message : 'unknown error'}
          </div>
        ) : (
          <div className="space-y-3 max-h-[60vh] overflow-y-auto pr-1">
            {dossier.blockers.length > 0 && (
              <Card className="border-red-300 bg-red-50">
                <CardHeader className="pb-2">
                  <CardTitle className="text-sm font-medium text-red-800 flex items-center gap-2">
                    <AlertTriangle className="h-4 w-4" aria-hidden /> Cannot archive
                  </CardTitle>
                </CardHeader>
                <CardContent className="text-sm text-red-700 space-y-1">
                  {dossier.blockers.map((b, i) => (
                    <p key={i}>{b}</p>
                  ))}
                </CardContent>
              </Card>
            )}

            {dossier.stakeLevel === 'high' && (
              <Card className="border-amber-300 bg-amber-50">
                <CardHeader className="pb-2">
                  <CardTitle className="text-sm font-medium text-amber-900 flex items-center gap-2">
                    <AlertTriangle className="h-4 w-4" aria-hidden />
                    Late-stage interest - confirmation required
                  </CardTitle>
                </CardHeader>
                <CardContent className="text-xs text-amber-900">
                  This client is at <Badge variant="secondary">{dossier.highStakesStage}</Badge>.
                  Provide a reason explaining why you&rsquo;re archiving them at this stage. The
                  reason is recorded in the audit log.
                </CardContent>
              </Card>
            )}

            {/* Interests + signed-doc acknowledgment */}
            {dossier.interests.length > 0 && (
              <Card>
                <CardHeader className="pb-2">
                  <CardTitle className="text-sm font-medium flex items-center gap-2">
                    <FileText className="h-4 w-4" aria-hidden /> Pipeline interests (
                    {dossier.interests.length})
                  </CardTitle>
                </CardHeader>
                <CardContent className="text-xs space-y-1">
                  {dossier.interests.map((i) => (
                    <div key={i.interestId} className="flex items-center justify-between">
                      <span className="font-mono">{i.interestId.slice(0, 8)}</span>
                      <span className="flex items-center gap-2">
                        <Badge variant="secondary" className="text-xs">
                          {stageLabelFor(i.pipelineStage)}
                        </Badge>
                        {i.hasSignedEoi && <Badge className="text-xs">Signed EOI</Badge>}
                      </span>
                    </div>
                  ))}
                </CardContent>
              </Card>
            )}

            {hasSignedDocs && (
              <Card className="border-blue-300 bg-blue-50">
                <CardContent className="pt-4 text-xs text-blue-900">
                  <label className="flex items-start gap-2 cursor-pointer">
                    <input
                      type="checkbox"
                      checked={acknowledged}
                      onChange={(e) => setAcknowledged(e.target.checked)}
                      className="mt-0.5"
                    />
                    <span>
                      I acknowledge this client has signed legal documents. The documents will be
                      retained in the system and remain binding regardless of archive status.
                    </span>
                  </label>
                </CardContent>
              </Card>
            )}

            {/* Berths */}
            {dossier.berths.length > 0 && (
              <Card>
                <CardHeader className="pb-2">
                  <CardTitle className="text-sm font-medium flex items-center gap-2">
                    <Anchor className="h-4 w-4" aria-hidden /> Berths ({dossier.berths.length})
                  </CardTitle>
                </CardHeader>
                <CardContent className="space-y-3">
                  {dossier.berths.map((b) => (
                    <div key={b.berthId} className="text-xs">
                      <div className="flex items-center justify-between mb-1">
                        <div className="flex items-center gap-2">
                          <span className="font-medium">Berth {b.mooringNumber}</span>
                          <Badge variant="secondary" className="text-xs">
                            {b.status}
                          </Badge>
                        </div>
                        <select
                          className="rounded border bg-background px-2 py-1 text-xs disabled:opacity-50"
                          value={berthDecisions[b.berthId] ?? 'retain'}
                          onChange={(e) =>
                            setBerthDecisions((prev) => ({
                              ...prev,
                              [b.berthId]: e.target.value as BerthAction,
                            }))
                          }
                          disabled={b.status === 'sold'}
                        >
                          <option value="retain">Retain on archived client</option>
                          <option value="release">Release to available</option>
                        </select>
                      </div>
                      {b.status === 'sold' && (
                        <p className="text-muted-foreground italic">
                          Sold berths stay sold. Process a refund separately if needed.
                        </p>
                      )}
                      {b.otherInterests.length > 0 && berthDecisions[b.berthId] === 'release' && (
                        <p className="text-muted-foreground">
                          Releasing will notify the sales rep. Other interests on this berth:{' '}
                          {b.otherInterests
                            .slice(0, 3)
                            .map(
                              (o) => `${o.clientName ?? '?'} (${stageLabelFor(o.pipelineStage)})`,
                            )
                            .join(', ')}
                          {b.otherInterests.length > 3 ? ` +${b.otherInterests.length - 3}` : ''}
                        </p>
                      )}
                    </div>
                  ))}
                </CardContent>
              </Card>
            )}

            {/* Yachts */}
            {dossier.yachts.length > 0 && (
              <Card>
                <CardHeader className="pb-2">
                  <CardTitle className="text-sm font-medium flex items-center gap-2">
                    <Ship className="h-4 w-4" aria-hidden /> Yachts owned ({dossier.yachts.length})
                  </CardTitle>
                </CardHeader>
                <CardContent className="space-y-2">
                  {dossier.yachts.map((y) => (
                    <div key={y.yachtId} className="flex items-center justify-between text-xs">
                      <span className="font-medium">{y.name}</span>
                      <select
                        className="rounded border bg-background px-2 py-1 text-xs"
                        value={yachtDecisions[y.yachtId] ?? 'retain'}
                        onChange={(e) =>
                          setYachtDecisions((prev) => ({
                            ...prev,
                            [y.yachtId]: e.target.value as YachtAction,
                          }))
                        }
                      >
                        <option value="retain">Leave on archived client</option>
                        <option value="mark_sold_away">Mark as sold-away</option>
                        {/* Transfer to another owner needs an owner picker; v1
                            offers retain + sold-away inline. Use the yacht
                            detail page to transfer to a specific owner. */}
                      </select>
                    </div>
                  ))}
                </CardContent>
              </Card>
            )}

            {/* Tenancies */}
            {dossier.tenancies.length > 0 && (
              <Card>
                <CardHeader className="pb-2">
                  <CardTitle className="text-sm font-medium flex items-center gap-2">
                    <Anchor className="h-4 w-4" aria-hidden /> Active tenancies (
                    {dossier.tenancies.length})
                  </CardTitle>
                </CardHeader>
                <CardContent className="space-y-2">
                  {dossier.tenancies.map((r) => (
                    <div key={r.tenancyId} className="flex items-center justify-between text-xs">
                      <span>Berth {r.mooringNumber}</span>
                      <select
                        className="rounded border bg-background px-2 py-1 text-xs"
                        value={tenancyDecisions[r.tenancyId] ?? 'cancel'}
                        onChange={(e) =>
                          setTenancyDecisions((prev) => ({
                            ...prev,
                            [r.tenancyId]: e.target.value as TenancyAction,
                          }))
                        }
                      >
                        <option value="cancel">Cancel tenancy</option>
                      </select>
                    </div>
                  ))}
                </CardContent>
              </Card>
            )}

            {/* Invoices */}
            {dossier.invoices.length > 0 && (
              <Card>
                <CardHeader className="pb-2">
                  <CardTitle className="text-sm font-medium flex items-center gap-2">
                    <Receipt className="h-4 w-4" aria-hidden /> Outstanding invoices (
                    {dossier.invoices.length})
                  </CardTitle>
                </CardHeader>
                <CardContent className="space-y-2">
                  {dossier.invoices.map((i) => (
                    <div key={i.invoiceId} className="flex items-center justify-between text-xs">
                      <span>
                        {i.invoiceNumber} · {i.total} {i.currency}
                      </span>
                      <select
                        className="rounded border bg-background px-2 py-1 text-xs"
                        value={invoiceDecisions[i.invoiceId] ?? 'leave'}
                        onChange={(e) =>
                          setInvoiceDecisions((prev) => ({
                            ...prev,
                            [i.invoiceId]: e.target.value as InvoiceAction,
                          }))
                        }
                      >
                        <option value="leave">Leave open</option>
                        <option value="void">Void</option>
                        <option value="write_off">Write off</option>
                      </select>
                    </div>
                  ))}
                </CardContent>
              </Card>
            )}

            {/* In-flight signing requests */}
            {dossier.documents.filter((d) => d.isInFlight).length > 0 && (
              <Card>
                <CardHeader className="pb-2">
                  <CardTitle className="text-sm font-medium flex items-center gap-2">
                    <FileText className="h-4 w-4" aria-hidden /> In-flight signing requests
                  </CardTitle>
                </CardHeader>
                <CardContent className="space-y-2">
                  {dossier.documents
                    .filter((d) => d.isInFlight)
                    .map((d) => (
                      <div key={d.documentId} className="flex items-center justify-between text-xs">
                        <span>{d.templateName ?? d.documentId.slice(0, 8)}</span>
                        <select
                          className="rounded border bg-background px-2 py-1 text-xs"
                          value={documentDecisions[d.documentId] ?? 'leave'}
                          onChange={(e) =>
                            setDocumentDecisions((prev) => ({
                              ...prev,
                              [d.documentId]: e.target.value as DocumentAction,
                            }))
                          }
                        >
                          <option value="leave">Leave signing request pending</option>
                          <option value="void_documenso">Cancel the signing request</option>
                        </select>
                      </div>
                    ))}
                </CardContent>
              </Card>
            )}

            {/* Auto-handled summary */}
            <Card className="border-muted">
              <CardHeader className="pb-2">
                <CardTitle className="text-sm font-medium flex items-center gap-2">
                  <Users className="h-4 w-4" aria-hidden /> Automatically handled
                </CardTitle>
              </CardHeader>
              <CardContent className="text-xs text-muted-foreground space-y-1">
                <p>EOI documents - retained for audit (always)</p>
                {dossier.hasPortalUser && <p>Portal user - deactivated (login revoked)</p>}
                {dossier.companies.length > 0 && (
                  <p>Company memberships - end-dated to today (history preserved)</p>
                )}
                <p>Notes, contacts, tags, addresses - survive on the archived client</p>
              </CardContent>
            </Card>

            {/* Reason field */}
            <div>
              <label className="text-xs uppercase tracking-wide text-muted-foreground">
                Reason {dossier.stakeLevel === 'high' && <span className="text-red-600">*</span>}
              </label>
              <Textarea
                value={reason}
                onChange={(e) => setReason(e.target.value)}
                placeholder={
                  dossier.stakeLevel === 'high'
                    ? `Why are you archiving this client at ${dossier.highStakesStage}?`
                    : 'Optional: why is this client being archived?'
                }
                className="mt-1 min-h-[60px]"
              />
            </div>
          </div>
        )}

        <DialogFooter>
          <Button variant="outline" onClick={() => onOpenChange(false)}>
            Cancel
          </Button>
          <Button
            disabled={!canSubmit || archiveMutation.isPending}
            onClick={() => archiveMutation.mutate()}
          >
            {archiveMutation.isPending ? (
              <Loader2 className="h-3.5 w-3.5 animate-spin mr-1.5" aria-hidden />
            ) : null}
            Archive
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
