'use client';

import { useCallback, useRef, useState } from 'react';
import { Upload, X } from 'lucide-react';

import { cn } from '@/lib/utils';

interface UploadingFile {
  id: string;
  name: string;
  progress: number;
  error?: string;
}

interface FileUploadZoneProps {
  entityType?: string;
  entityId?: string;
  clientId?: string;
  yachtId?: string;
  companyId?: string;
  /**
   * Optional interest FK. When supplied alongside `clientId`, the rep
   * picks whether to file the upload at the deal level
   * (`Clients/<Name>/<Interest folder>/`) or the client level
   * (`Clients/<Name>/`) via the scope radio. When omitted the radio
   * is hidden and the upload always files at whichever entity-scope
   * the caller passed.
   */
  interestId?: string;
  /**
   * Optional folder to deposit the file into. Hub uploads pass the
   * currently-selected folderId so files land where the user expects.
   */
  folderId?: string | null;
  /**
   * Fires per successful upload with the file metadata. The wizard /
   * inline-upload flows use the returned id to wire follow-up actions
   * (e.g. set as the source PDF for a Documenso signing flow).
   */
  onUploadComplete?: (file?: { id: string; filename?: string }) => void;
}

export function FileUploadZone({
  entityType,
  entityId,
  clientId,
  yachtId,
  companyId,
  interestId,
  folderId,
  onUploadComplete,
}: FileUploadZoneProps) {
  const [isDragOver, setIsDragOver] = useState(false);
  const [uploading, setUploading] = useState<UploadingFile[]>([]);
  const inputRef = useRef<HTMLInputElement>(null);
  // Scope toggle - only meaningful when an interest is being uploaded
  // FROM (i.e. the rep is on the InterestDocumentsTab). Default to the
  // narrower "deal" scope so a rep uploading a contract specific to this
  // deal doesn't accidentally surface it under every interest the client
  // ever had. They can flip to client-level for shared docs (passport,
  // KYC, etc.).
  const [scope, setScope] = useState<'interest' | 'client'>(interestId ? 'interest' : 'client');

  const uploadFiles = useCallback(
    async (fileList: FileList) => {
      const newUploads: UploadingFile[] = Array.from(fileList).map((f) => ({
        id: crypto.randomUUID(),
        name: f.name,
        progress: 0,
      }));
      setUploading((prev) => [...prev, ...newUploads]);

      await Promise.all(
        Array.from(fileList).map(async (file, i) => {
          const uploadId = newUploads[i]!.id;
          try {
            const formData = new FormData();
            formData.append('file', file);
            formData.append('filename', file.name);
            if (clientId) formData.append('clientId', clientId);
            if (yachtId) formData.append('yachtId', yachtId);
            if (companyId) formData.append('companyId', companyId);
            // Scope-aware: when the rep picked "This deal" send the
            // interest FK so the service files the row at the nested
            // Interest folder; when they picked "Client-level" omit the
            // interest FK so it lands at the client folder.
            if (interestId && scope === 'interest') {
              formData.append('interestId', interestId);
            }
            if (entityType) formData.append('entityType', entityType);
            if (entityId) formData.append('entityId', entityId);
            if (folderId) formData.append('folderId', folderId);

            setUploading((prev) =>
              prev.map((u) => (u.id === uploadId ? { ...u, progress: 50 } : u)),
            );

            // Use fetch directly for FormData (apiFetch JSON-encodes body)
            const portId = (await import('@/stores/ui-store')).useUIStore.getState().currentPortId;
            const headers = new Headers();
            if (portId) headers.set('X-Port-Id', portId);
            const uploadRes = await fetch('/api/v1/files/upload', {
              method: 'POST',
              headers,
              credentials: 'include',
              body: formData,
            });
            if (!uploadRes.ok) {
              throw new Error('Upload failed');
            }

            const uploadJson = (await uploadRes.json().catch(() => null)) as {
              data?: { id?: string; filename?: string };
            } | null;
            if (uploadJson?.data?.id) {
              onUploadComplete?.({
                id: uploadJson.data.id,
                filename: uploadJson.data.filename,
              });
            }

            setUploading((prev) =>
              prev.map((u) => (u.id === uploadId ? { ...u, progress: 100 } : u)),
            );
          } catch {
            setUploading((prev) =>
              prev.map((u) => (u.id === uploadId ? { ...u, error: 'Upload failed' } : u)),
            );
          }
        }),
      );

      // Clear completed uploads after a moment
      setTimeout(() => {
        setUploading((prev) => prev.filter((u) => u.error));
        onUploadComplete?.();
      }, 1500);
    },
    [clientId, yachtId, companyId, entityType, entityId, folderId, onUploadComplete],
  );

  const handleDrop = useCallback(
    (e: React.DragEvent<HTMLDivElement>) => {
      e.preventDefault();
      setIsDragOver(false);
      if (e.dataTransfer.files.length > 0) {
        void uploadFiles(e.dataTransfer.files);
      }
    },
    [uploadFiles],
  );

  const handleChange = useCallback(
    (e: React.ChangeEvent<HTMLInputElement>) => {
      if (e.target.files && e.target.files.length > 0) {
        void uploadFiles(e.target.files);
        e.target.value = '';
      }
    },
    [uploadFiles],
  );

  return (
    <div className="space-y-3">
      {/* Scope radio - only renders when an interest FK is present. The
          rep picks whether the upload files at the deal level (nested
          under Clients/<Name>/<Interest>) or the client level
          (Clients/<Name>). Default = deal, since that's the narrower
          filing path and reps almost always upload deal-specific docs
          here. */}
      {interestId ? (
        <fieldset className="flex flex-wrap items-center gap-3 rounded-md border bg-muted/30 px-3 py-2 text-xs">
          <legend className="px-1 font-semibold uppercase tracking-wide text-muted-foreground">
            File at
          </legend>
          <label className="inline-flex cursor-pointer items-center gap-1.5">
            <input
              type="radio"
              name="upload-scope"
              checked={scope === 'interest'}
              onChange={() => setScope('interest')}
            />
            <span>This deal</span>
          </label>
          <label className="inline-flex cursor-pointer items-center gap-1.5">
            <input
              type="radio"
              name="upload-scope"
              checked={scope === 'client'}
              onChange={() => setScope('client')}
            />
            <span>Client-level (all deals)</span>
          </label>
        </fieldset>
      ) : null}
      <div
        role="button"
        tabIndex={0}
        className={cn(
          'flex flex-col items-center justify-center rounded-lg border-2 border-dashed p-8 transition-colors cursor-pointer',
          isDragOver
            ? 'border-primary bg-primary/5'
            : 'border-muted-foreground/25 hover:border-primary/50 hover:bg-muted/30',
        )}
        onDragOver={(e) => {
          e.preventDefault();
          setIsDragOver(true);
        }}
        onDragLeave={() => setIsDragOver(false)}
        onDrop={handleDrop}
        onClick={() => inputRef.current?.click()}
        onKeyDown={(e) => {
          if (e.key === 'Enter' || e.key === ' ') inputRef.current?.click();
        }}
      >
        <Upload className="h-8 w-8 text-muted-foreground mb-2" />
        <p className="text-sm font-medium">Drop files here or click to upload</p>
        <p className="text-xs text-muted-foreground mt-1">PDF, Word, Excel, images up to 50MB</p>
        <input
          ref={inputRef}
          type="file"
          multiple
          className="hidden"
          onChange={handleChange}
          accept=".jpg,.jpeg,.png,.gif,.webp,.pdf,.doc,.docx,.xls,.xlsx,.txt,.csv"
        />
      </div>

      {uploading.length > 0 && (
        <div className="space-y-2">
          {uploading.map((u) => (
            <div key={u.id} className="flex items-center gap-3 text-sm">
              <span className="flex-1 truncate">{u.name}</span>
              {u.error ? (
                <span className="text-destructive text-xs">{u.error}</span>
              ) : (
                <div className="flex items-center gap-2">
                  <div className="h-1.5 w-24 rounded-full bg-muted overflow-hidden">
                    <div
                      className="h-full rounded-full bg-primary transition-all"
                      style={{ width: `${u.progress}%` }}
                    />
                  </div>
                  <span className="text-xs text-muted-foreground">{u.progress}%</span>
                </div>
              )}
              {u.error && (
                <button
                  type="button"
                  onClick={() => setUploading((prev) => prev.filter((x) => x.id !== u.id))}
                >
                  <X className="h-3.5 w-3.5 text-muted-foreground" />
                </button>
              )}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}
