'use client';

import { useState, useRef, DragEvent } from 'react';
import { X, Upload, CheckCircle, AlertCircle, Loader2 } from 'lucide-react';

interface Props {
  folderId: number;
  onClose:  () => void;
  onDone:   () => void;
}

interface FileState {
  file:     File;
  status:   'pending' | 'uploading' | 'done' | 'error';
  progress: number;
  error?:   string;
}

const MAX_MB = Number(process.env.NEXT_PUBLIC_MAX_FILE_MB ?? 100);

export default function UploadModal({ folderId, onClose, onDone }: Props) {
  const [files,   setFiles]   = useState<FileState[]>([]);
  const [dragging, setDragging] = useState(false);
  const [uploading, setUploading] = useState(false);
  const inputRef = useRef<HTMLInputElement>(null);

  function addFiles(selected: FileList | null) {
    if (!selected) return;
    const newFiles: FileState[] = Array.from(selected).map((f) => ({
      file: f, status: 'pending', progress: 0,
    }));
    setFiles((prev) => [...prev, ...newFiles]);
  }

  function onDrop(e: DragEvent) {
    e.preventDefault();
    setDragging(false);
    addFiles(e.dataTransfer.files);
  }

  function removeFile(idx: number) {
    setFiles((prev) => prev.filter((_, i) => i !== idx));
  }

  async function uploadOne(idx: number, fs: FileState): Promise<void> {
    const { file } = fs;

    if (file.size > MAX_MB * 1024 * 1024) {
      setFiles((prev) =>
        prev.map((f, i) => i === idx ? { ...f, status: 'error', error: `Exceeds ${MAX_MB} MB` } : f)
      );
      return;
    }

    setFiles((prev) =>
      prev.map((f, i) => i === idx ? { ...f, status: 'uploading', progress: 5 } : f)
    );

    try {
      // 1. Get presigned URL
      const presignRes = await fetch('/api/s3/presigned-upload', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          filename:    file.name,
          contentType: file.type || 'application/octet-stream',
          size:        file.size,
          folderId,
        }),
      });
      if (!presignRes.ok) throw new Error('Could not get upload URL');
      const { uploadUrl, s3Key } = await presignRes.json();

      // 2. PUT directly to S3 — tracks progress with XMLHttpRequest
      await new Promise<void>((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('PUT', uploadUrl);
        xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream');

        xhr.upload.onprogress = (ev) => {
          if (ev.lengthComputable) {
            const pct = Math.round((ev.loaded / ev.total) * 90) + 5;
            setFiles((prev) =>
              prev.map((f, i) => i === idx ? { ...f, progress: pct } : f)
            );
          }
        };
        xhr.onload  = () => (xhr.status < 400 ? resolve() : reject(new Error('S3 upload failed')));
        xhr.onerror = () => reject(new Error('Network error'));
        xhr.send(file);
      });

      // 3. Register in DB
      const regRes = await fetch('/api/files', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          name:         file.name,
          originalName: file.name,
          s3Key,
          size:         file.size,
          mimeType:     file.type || 'application/octet-stream',
          folderId,
        }),
      });
      if (!regRes.ok) throw new Error('Could not register file');

      setFiles((prev) =>
        prev.map((f, i) => i === idx ? { ...f, status: 'done', progress: 100 } : f)
      );
    } catch (err: unknown) {
      const msg = err instanceof Error ? err.message : 'Upload failed';
      setFiles((prev) =>
        prev.map((f, i) => i === idx ? { ...f, status: 'error', error: msg } : f)
      );
    }
  }

  async function startUpload() {
    setUploading(true);
    const pending = files
      .map((f, i) => ({ f, i }))
      .filter(({ f }) => f.status === 'pending');

    // Upload all concurrently (S3 handles it fine)
    await Promise.all(pending.map(({ f, i }) => uploadOne(i, f)));
    setUploading(false);

    // Always call onDone after uploads complete to refresh file list
    setTimeout(onDone, 300);
  }

  const hasPending = files.some((f) => f.status === 'pending');

  return (
    <div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center p-4 bg-black/40">
      <div className="card w-full max-w-lg max-h-[90vh] flex flex-col animate-in slide-in-from-bottom sm:slide-in-from-bottom-0">
        {/* Header */}
        <div className="flex items-center justify-between border-b border-slate-200 px-5 py-4">
          <h2 className="font-semibold text-slate-800">Upload Files</h2>
          <button onClick={onClose} className="rounded-lg p-1.5 hover:bg-slate-100">
            <X className="h-4 w-4" />
          </button>
        </div>

        <div className="flex-1 overflow-y-auto p-5 space-y-4">
          {/* Drop zone */}
          <div
            onDragOver={(e) => { e.preventDefault(); setDragging(true); }}
            onDragLeave={() => setDragging(false)}
            onDrop={onDrop}
            onClick={() => inputRef.current?.click()}
            className={`flex cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed px-4 py-8 transition-colors
              ${dragging ? 'border-blue-400 bg-blue-50' : 'border-slate-200 hover:border-blue-300 hover:bg-slate-50'}`}
          >
            <Upload className="mb-2 h-8 w-8 text-slate-400" />
            <p className="text-sm font-medium text-slate-700">Drop files or click to browse</p>
            <p className="mt-1 text-xs text-slate-400">Max {MAX_MB} MB per file · All types allowed</p>
            <input
              ref={inputRef}
              type="file"
              multiple
              className="hidden"
              onChange={(e) => addFiles(e.target.files)}
            />
          </div>

          {/* File list */}
          {files.length > 0 && (
            <ul className="space-y-2">
              {files.map((f, i) => (
                <li key={i} className="flex items-center gap-3 rounded-lg border border-slate-200 px-3 py-2">
                  <div className="flex-1 min-w-0">
                    <p className="truncate text-sm font-medium text-slate-700">{f.file.name}</p>
                    {f.status === 'uploading' && (
                      <div className="mt-1 h-1.5 w-full overflow-hidden rounded-full bg-slate-100">
                        <div
                          className="h-full rounded-full bg-blue-500 transition-all"
                          style={{ width: `${f.progress}%` }}
                        />
                      </div>
                    )}
                    {f.status === 'error' && (
                      <p className="text-xs text-red-500">{f.error}</p>
                    )}
                  </div>

                  {f.status === 'pending'   && <button onClick={() => removeFile(i)} className="text-slate-400 hover:text-red-500"><X className="h-4 w-4" /></button>}
                  {f.status === 'uploading' && <Loader2 className="h-4 w-4 animate-spin text-blue-500" />}
                  {f.status === 'done'      && <CheckCircle className="h-4 w-4 text-green-500" />}
                  {f.status === 'error'     && <AlertCircle className="h-4 w-4 text-red-500" />}
                </li>
              ))}
            </ul>
          )}
        </div>

        {/* Footer */}
        <div className="flex items-center justify-end gap-2 border-t border-slate-200 px-5 py-4">
          <button onClick={onClose} className="btn-secondary">Cancel</button>
          <button
            onClick={startUpload}
            disabled={!hasPending || uploading}
            className="btn-primary"
          >
            {uploading ? (
              <><Loader2 className="h-4 w-4 animate-spin" /> Uploading…</>
            ) : (
              <><Upload className="h-4 w-4" /> Upload {files.filter(f => f.status === 'pending').length} file(s)</>
            )}
          </button>
        </div>
      </div>
    </div>
  );
}
