'use client';

import { useMemo, useState } from 'react';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { AlertTriangle, Loader2, XCircle } 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 { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { Textarea } from '@/components/ui/textarea';
import { apiFetch } from '@/lib/api/client';
import { toastError } from '@/lib/api/toast-error';

interface Signer {
  id: string;
  signerName: string;
  signerEmail: string;
  signerRole: string;
  status: string;
}

interface EoiCancelDialogProps {
  documentId: string;
  signers: Signer[];
  open: boolean;
  onOpenChange: (open: boolean) => void;
}

/**
 * Cancel-with-notify modal. Two variants by signedCount:
 *   - 0 signed: simple confirm with optional reason. Cancel button.
 *   - 1+ signed: list each signer with a checkbox so the rep picks
 *     who to email. Pre-checks the signers who have signed (they're
 *     the most-affected) - rep can opt out.
 *
 * In both cases the reason textarea is optional and (when present)
 * gets inlined into the cancellation email body + the audit log.
 *
 * On confirm: POST /api/v1/documents/[id]/cancel with
 *   { reason, notifyRecipients: [signerId, ...] }
 * The server voids the envelope, marks status=cancelled, sends the
 * branded cancellation email to each picked recipient.
 */
export function EoiCancelDialog({ documentId, signers, open, onOpenChange }: EoiCancelDialogProps) {
  const queryClient = useQueryClient();
  const [reason, setReason] = useState('');
  const [cancelMode, setCancelMode] = useState<'delete' | 'keep_remote'>('delete');
  const [notifyIds, setNotifyIds] = useState<Set<string>>(() => {
    // Default: pre-check the signers who have signed - they're the
    // recipients most likely to want to know. Pending signers can be
    // notified too but the rep needs to opt them in.
    return new Set(signers.filter((s) => s.status === 'signed').map((s) => s.id));
  });

  const signedCount = useMemo(() => signers.filter((s) => s.status === 'signed').length, [signers]);

  const cancelMutation = useMutation({
    mutationFn: () =>
      apiFetch(`/api/v1/documents/${documentId}/cancel`, {
        method: 'POST',
        body: {
          reason: reason.trim() || null,
          notifyRecipients: Array.from(notifyIds),
          cancelMode,
        },
      }),
    onSuccess: () => {
      queryClient.invalidateQueries({ predicate: (q) => q.queryKey[0] === 'documents' });
      const base =
        notifyIds.size > 0
          ? `EOI cancelled. ${notifyIds.size} signer${notifyIds.size === 1 ? '' : 's'} notified.`
          : 'EOI cancelled.';
      toast.success(
        cancelMode === 'keep_remote' ? `${base} Envelope kept on Documenso for audit.` : base,
      );
      onOpenChange(false);
      // Reset internal state so a second open of the dialog starts clean.
      setReason('');
      setNotifyIds(new Set());
      setCancelMode('delete');
    },
    onError: (err) => toastError(err),
  });

  const toggle = (id: string) => {
    setNotifyIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  };

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="sm:max-w-md">
        <DialogHeader>
          <DialogTitle className="flex items-center gap-2">
            <AlertTriangle className="size-4 text-amber-600" aria-hidden /> Cancel this EOI?
          </DialogTitle>
          <DialogDescription>
            {signedCount === 0
              ? 'No signatures have been collected yet. The signing service will be told to void this envelope.'
              : `${signedCount} signer${signedCount === 1 ? ' has' : 's have'} already signed. The envelope will be voided and pick the signers you want to notify by email below.`}
          </DialogDescription>
        </DialogHeader>

        {signedCount > 0 && (
          <div className="space-y-2 rounded-md border bg-muted/30 p-3">
            <p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
              Notify
            </p>
            <ul className="space-y-1.5">
              {signers.map((s) => (
                <li key={s.id} className="flex items-center gap-2 text-sm">
                  <Checkbox
                    id={`notify-${s.id}`}
                    checked={notifyIds.has(s.id)}
                    onCheckedChange={() => toggle(s.id)}
                  />
                  <Label htmlFor={`notify-${s.id}`} className="flex-1 cursor-pointer font-normal">
                    <span className="font-medium">{s.signerName || s.signerEmail}</span>{' '}
                    <span className="text-xs text-muted-foreground">
                      · {s.signerRole}
                      {s.status === 'signed' ? ' · already signed' : ' · pending'}
                    </span>
                  </Label>
                </li>
              ))}
            </ul>
            <p className="text-xs italic text-muted-foreground">
              Leave all unchecked to cancel silently - no emails will be sent.
            </p>
          </div>
        )}

        <div className="space-y-1.5">
          <p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
            Documenso envelope
          </p>
          <RadioGroup
            value={cancelMode}
            onValueChange={(value) => setCancelMode(value as 'delete' | 'keep_remote')}
            className="gap-2"
          >
            <label
              htmlFor="eoi-cancel-mode-delete"
              className="flex cursor-pointer items-start gap-3 rounded-md border p-2.5 hover:bg-accent/40"
            >
              <RadioGroupItem id="eoi-cancel-mode-delete" value="delete" className="mt-0.5" />
              <span className="space-y-0.5">
                <span className="block text-sm font-medium">Delete from Documenso</span>
                <span className="block text-xs text-muted-foreground">
                  Frees the upstream envelope slot. Default - keeps the Documenso log clean.
                </span>
              </span>
            </label>
            <label
              htmlFor="eoi-cancel-mode-keep"
              className="flex cursor-pointer items-start gap-3 rounded-md border p-2.5 hover:bg-accent/40"
            >
              <RadioGroupItem id="eoi-cancel-mode-keep" value="keep_remote" className="mt-0.5" />
              <span className="space-y-0.5">
                <span className="block text-sm font-medium">Keep on Documenso for audit</span>
                <span className="block text-xs text-muted-foreground">
                  Leaves the envelope intact. Local copy still flips to Cancelled.
                </span>
              </span>
            </label>
          </RadioGroup>
        </div>

        <div className="space-y-1.5">
          <Label htmlFor="cancel-reason" className="text-xs font-semibold uppercase tracking-wide">
            Reason (optional)
          </Label>
          <Textarea
            id="cancel-reason"
            value={reason}
            onChange={(e) => setReason(e.target.value)}
            placeholder="e.g. Yacht owner changed terms; will resend a fresh EOI."
            className="min-h-[80px] resize-y"
            maxLength={2000}
          />
          <p className="text-xs text-muted-foreground">
            Appears in the cancellation email (if you notify anyone) and the audit log.
          </p>
        </div>

        <DialogFooter className="gap-2">
          <Button variant="outline" onClick={() => onOpenChange(false)}>
            Keep EOI
          </Button>
          <Button
            variant="destructive"
            onClick={() => cancelMutation.mutate()}
            disabled={cancelMutation.isPending}
            className="gap-1.5 [&_svg]:size-3.5"
          >
            {cancelMutation.isPending ? (
              <Loader2 className="animate-spin" aria-hidden />
            ) : (
              <XCircle />
            )}
            Cancel EOI
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
