'use client';

import { useRef, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { CheckCircle2, FileUp, Trophy, Loader2 } from 'lucide-react';
import { toast } from 'sonner';

import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { apiFetch } from '@/lib/api/client';
import { cn } from '@/lib/utils';

/**
 * Won-status manual-upload panel.
 *
 * Renders only when the interest's outcome is `won`. Detects whether
 * a Contract / EOI / Other doc is already attached (via the existing
 * files endpoint) and shows an "Upload {missing}" slot for each one
 * that isn't there yet. Naturally hides itself once the rep has filed
 * everything.
 *
 * Reps that reached Won through the natural EOI → Contract → Deposit
 * chain will typically see all three slots already filled and the
 * panel collapses to a green confirmation strip.
 */
interface WonStatusPanelProps {
  interestId: string;
  /** Outcome of the interest. Panel hides unless 'won'. */
  outcome: string | null;
}

interface FileRow {
  id: string;
  category: string | null;
  filename: string;
  originalName: string | null;
}

interface FilesResponse {
  data: FileRow[];
}

interface UploadSlot {
  key: 'contract' | 'eoi' | 'other';
  label: string;
  description: string;
  category: string;
}

const SLOTS: UploadSlot[] = [
  {
    key: 'contract',
    label: 'Signed contract',
    description: 'Final purchase / lease agreement signed by both sides.',
    category: 'contract',
  },
  {
    key: 'eoi',
    label: 'Signed EOI',
    description: "Required only if you didn't run the EOI through the in-app signing flow.",
    category: 'eoi',
  },
  {
    key: 'other',
    label: 'Other supporting docs',
    description: 'Insurance certificates, ID, anything else worth attaching to the closed deal.',
    category: 'other',
  },
];

export function WonStatusPanel({ interestId, outcome }: WonStatusPanelProps) {
  const qc = useQueryClient();

  // Fetch the files attached to this interest so we can hide slots that
  // are already filled. The endpoint accepts `entityType` + `entityId`
  // for polymorphic ownership; non-interest files are filtered out.
  const { data } = useQuery<FilesResponse>({
    queryKey: ['interest-files', interestId],
    queryFn: () => apiFetch(`/api/v1/files?entityType=interest&entityId=${interestId}&limit=100`),
    enabled: outcome === 'won',
    staleTime: 30_000,
  });

  const existing = data?.data ?? [];

  if (outcome !== 'won') return null;

  const slots = SLOTS.map((s) => ({
    ...s,
    files: existing.filter((f) => (f.category ?? '').toLowerCase() === s.category),
  }));

  const allFilled = slots[0]!.files.length > 0 && slots[1]!.files.length > 0;

  return (
    <Card className="border-emerald-200 bg-emerald-50/40">
      <CardHeader className="gap-1">
        <CardTitle className="flex items-center gap-2 text-base text-emerald-900">
          <Trophy className="size-4" aria-hidden />
          Won - wrap-up checklist
        </CardTitle>
        <p className="text-xs text-emerald-800/80">
          Upload anything that didn&apos;t flow through the system automatically. Tenancies, deposit
          invoicing, and client billing are handled outside the CRM - this checklist is for the
          paperwork that lives on the deal itself.
        </p>
      </CardHeader>
      <CardContent className="space-y-2">
        {slots.map((s) => (
          <UploadSlotRow
            key={s.key}
            slot={s}
            interestId={interestId}
            onUploaded={() => qc.invalidateQueries({ queryKey: ['interest-files', interestId] })}
          />
        ))}
        {allFilled ? (
          <p className="pt-1 text-xs text-emerald-800/80 italic">
            All required documents are attached. Anything else you upload here will appear in the
            client&apos;s signed-docs folder.
          </p>
        ) : null}
      </CardContent>
    </Card>
  );
}

function UploadSlotRow({
  slot,
  interestId,
  onUploaded,
}: {
  slot: UploadSlot & { files: FileRow[] };
  interestId: string;
  onUploaded: () => void;
}) {
  const inputRef = useRef<HTMLInputElement>(null);
  const [uploading, setUploading] = useState(false);

  const filled = slot.files.length > 0;

  const upload = useMutation({
    mutationFn: async (file: File) => {
      const fd = new FormData();
      fd.append('file', file);
      fd.append('entityType', 'interest');
      fd.append('entityId', interestId);
      fd.append('category', slot.category);
      const res = await fetch('/api/v1/files/upload', { method: 'POST', body: fd });
      if (!res.ok) {
        const payload = (await res.json().catch(() => ({}))) as { error?: { message?: string } };
        throw new Error(payload.error?.message ?? `Upload failed (${res.status})`);
      }
    },
    onMutate: () => setUploading(true),
    onSuccess: () => {
      toast.success(`${slot.label} uploaded`);
      onUploaded();
    },
    onError: (err) => toast.error(err instanceof Error ? err.message : 'Upload failed'),
    onSettled: () => setUploading(false),
  });

  return (
    <div
      className={cn(
        'rounded-md border p-3 text-sm',
        filled ? 'border-emerald-300 bg-white' : 'border-input bg-card',
      )}
    >
      <div className="flex flex-wrap items-start justify-between gap-2">
        <div className="min-w-0">
          <div className="flex items-center gap-2 font-medium">
            {filled ? <CheckCircle2 className="size-4 text-emerald-600" aria-hidden /> : null}
            {slot.label}
            {filled ? (
              <span className="text-xs font-normal text-muted-foreground">
                ({slot.files.length} on file)
              </span>
            ) : null}
          </div>
          <p className="text-xs text-muted-foreground">{slot.description}</p>
        </div>
        <Button
          type="button"
          size="sm"
          variant={filled ? 'outline' : 'default'}
          onClick={() => inputRef.current?.click()}
          disabled={uploading}
        >
          {uploading ? (
            <Loader2 className="mr-1.5 size-3.5 animate-spin" aria-hidden />
          ) : (
            <FileUp className="mr-1.5 size-3.5" aria-hidden />
          )}
          {filled ? 'Add another' : 'Upload'}
        </Button>
        <input
          ref={inputRef}
          type="file"
          className="hidden"
          onChange={(e) => {
            const f = e.target.files?.[0];
            if (f) upload.mutate(f);
            e.target.value = '';
          }}
        />
      </div>
    </div>
  );
}
