'use client';

import { useState } from 'react';
import { Download, FolderInput } from 'lucide-react';
import { useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';

import { toastError } from '@/lib/api/toast-error';

import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { FilePreviewDialog } from '@/components/files/file-preview-dialog';
import { PermissionGate } from '@/components/shared/permission-gate';
import { usePaginatedQuery } from '@/hooks/use-paginated-query';
import { useConfirmation } from '@/hooks/use-confirmation';
import { apiFetch } from '@/lib/api/client';
import { triggerUrlDownload } from '@/lib/utils/download';
import { MoveToFolderDialog } from './move-to-folder-dialog';

interface DocumentRow {
  id: string;
  documentType: string;
  title: string;
  status: string;
  createdAt: string;
  folderId: string | null;
  /** When set, the doc has a downloaded signed PDF the rep can preview/download. */
  signedFileId?: string | null;
  signers?: Array<{ status: string }>;
}

interface DocumentListProps {
  interestId?: string;
  clientId?: string;
  /** Override the default empty state ("No documents yet.") with a contextual
   *  CTA - e.g. on the interest Documents tab we render a Generate EOI prompt. */
  emptyState?: React.ReactNode;
}

const STATUS_COLORS: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {
  draft: 'secondary',
  sent: 'default',
  partially_signed: 'default',
  completed: 'outline',
  expired: 'destructive',
  cancelled: 'destructive',
};

const TYPE_LABELS: Record<string, string> = {
  eoi: 'EOI',
  contract: 'Contract',
  nda: 'NDA',
  reservation_agreement: 'Reservation',
  other: 'Other',
};

interface DocRowProps {
  doc: DocumentRow;
  onDelete: (doc: DocumentRow) => void;
  onSend: (doc: DocumentRow) => void;
  onPreview: (fileId: string, fileName: string) => void;
}

async function downloadSignedFile(fileId: string, fallbackName: string) {
  try {
    const res = await apiFetch<{ data: { url: string; filename: string } }>(
      `/api/v1/files/${fileId}/download`,
    );
    triggerUrlDownload(res.data.url, res.data.filename || fallbackName);
  } catch {
    // silent - toast handled by the presign route on its own
  }
}

function DocRow({ doc, onDelete, onSend, onPreview }: DocRowProps) {
  const [moveOpen, setMoveOpen] = useState(false);
  const hasSignedFile = !!doc.signedFileId;

  const signerProgress = (() => {
    if (!doc.signers) return '-';
    const signed = doc.signers.filter((s) => s.status === 'signed').length;
    return `${signed}/${doc.signers.length} signed`;
  })();

  return (
    <>
      <tr className="border-b last:border-0 hover:bg-muted/20">
        <td className="px-4 py-3">
          <Badge variant="outline">{TYPE_LABELS[doc.documentType] ?? doc.documentType}</Badge>
        </td>
        <td className="px-4 py-3 font-medium">
          {hasSignedFile ? (
            <button
              type="button"
              onClick={() => onPreview(doc.signedFileId!, doc.title)}
              className="text-left hover:underline focus:outline-none focus:underline"
            >
              {doc.title}
            </button>
          ) : (
            doc.title
          )}
        </td>
        <td className="px-4 py-3">
          <Badge variant={STATUS_COLORS[doc.status] ?? 'default'}>{doc.status}</Badge>
        </td>
        <td className="px-4 py-3 text-muted-foreground">{signerProgress}</td>
        <td className="px-4 py-3 text-muted-foreground">
          {new Date(doc.createdAt).toLocaleDateString(undefined)}
        </td>
        <td className="px-4 py-3 text-right">
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button variant="ghost" size="sm">
                &hellip;
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="end">
              {hasSignedFile && (
                <DropdownMenuItem onClick={() => downloadSignedFile(doc.signedFileId!, doc.title)}>
                  <Download className="mr-2 h-4 w-4" aria-hidden />
                  Download
                </DropdownMenuItem>
              )}
              {doc.status === 'draft' && (
                <PermissionGate resource="documents" action="send_for_signing">
                  <DropdownMenuItem onClick={() => onSend(doc)}>Send for Signing</DropdownMenuItem>
                </PermissionGate>
              )}
              <PermissionGate resource="documents" action="manage_folders">
                <DropdownMenuItem onSelect={() => setMoveOpen(true)}>
                  <FolderInput className="mr-2 h-4 w-4" aria-hidden />
                  Move to folder…
                </DropdownMenuItem>
              </PermissionGate>
              <PermissionGate resource="documents" action="delete">
                <DropdownMenuItem
                  onClick={() => onDelete(doc)}
                  className="text-destructive focus:text-destructive"
                >
                  Delete
                </DropdownMenuItem>
              </PermissionGate>
            </DropdownMenuContent>
          </DropdownMenu>
        </td>
      </tr>
      <MoveToFolderDialog
        documentId={doc.id}
        documentTitle={doc.title}
        currentFolderId={doc.folderId ?? null}
        open={moveOpen}
        onOpenChange={setMoveOpen}
      />
    </>
  );
}

export function DocumentList({ interestId, clientId, emptyState }: DocumentListProps) {
  const queryClient = useQueryClient();
  const { confirm, dialog: confirmDialog } = useConfirmation();
  const [previewFile, setPreviewFile] = useState<{ id: string; name: string } | null>(null);

  const queryParams = new URLSearchParams();
  if (interestId) queryParams.set('interestId', interestId);
  if (clientId) queryParams.set('clientId', clientId);

  const { data, isLoading } = usePaginatedQuery<DocumentRow>({
    queryKey: ['documents', { interestId, clientId }],
    endpoint: `/api/v1/documents?${queryParams.toString()}`,
    filterDefinitions: [],
  });

  const handleDelete = async (doc: DocumentRow) => {
    const ok = await confirm({
      title: 'Delete document',
      description: `Delete "${doc.title}"? This cannot be undone.`,
      confirmLabel: 'Delete',
    });
    if (!ok) return;
    try {
      await apiFetch(`/api/v1/documents/${doc.id}`, { method: 'DELETE' });
      // Broader predicate matches every documents query (interest tab
      // counter, doc detail, hub root, etc.) so the row disappears
      // everywhere without requiring per-key invalidation knowledge.
      queryClient.invalidateQueries({ predicate: (q) => q.queryKey[0] === 'documents' });
      toast.success('Document deleted');
    } catch (err) {
      toastError(err);
    }
  };

  const handleSend = async (doc: DocumentRow) => {
    try {
      await apiFetch(`/api/v1/documents/${doc.id}/send`, { method: 'POST' });
      queryClient.invalidateQueries({ predicate: (q) => q.queryKey[0] === 'documents' });
      toast.success('Sent for signing');
    } catch (err) {
      toastError(err);
    }
  };

  if (isLoading) {
    return (
      <div className="py-8 text-center text-sm text-muted-foreground">Loading documents...</div>
    );
  }

  if (!data || data.length === 0) {
    if (emptyState) return <>{emptyState}</>;
    return <div className="py-8 text-center text-sm text-muted-foreground">No documents yet.</div>;
  }

  return (
    <div className="rounded-md border">
      <table className="w-full text-sm">
        <thead>
          <tr className="border-b bg-muted/50">
            <th className="px-4 py-3 text-left font-medium">Type</th>
            <th className="px-4 py-3 text-left font-medium">Title</th>
            <th className="px-4 py-3 text-left font-medium">Status</th>
            <th className="px-4 py-3 text-left font-medium">Signers</th>
            <th className="px-4 py-3 text-left font-medium">Created</th>
            <th className="px-4 py-3 text-right font-medium">Actions</th>
          </tr>
        </thead>
        <tbody>
          {data.map((doc) => (
            <DocRow
              key={doc.id}
              doc={doc}
              onDelete={handleDelete}
              onSend={handleSend}
              onPreview={(id, name) => setPreviewFile({ id, name })}
            />
          ))}
        </tbody>
      </table>
      {confirmDialog}
      <FilePreviewDialog
        open={!!previewFile}
        onOpenChange={(o) => {
          if (!o) setPreviewFile(null);
        }}
        fileId={previewFile?.id}
        fileName={previewFile?.name}
      />
    </div>
  );
}
