"use client";

import * as React from "react";
import { useCallback } from "react";
import { useDropzone } from "react-dropzone";
import { X, Upload, File, Image, FileText, Loader2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Progress } from "@/components/ui/progress";
import { cn } from "@/lib/utils";

export interface FileUploadProps {
  value?: string[];
  onChange: (files: string[]) => void;
  maxFiles?: number;
  maxSize?: number; // in bytes
  accept?: Record<string, string[]>;
  disabled?: boolean;
  className?: string;
  placeholder?: string;
}

interface UploadingFile {
  file: File;
  progress: number;
  url?: string;
  error?: string;
}

const FileUpload = React.forwardRef<HTMLDivElement, FileUploadProps>(
  ({ 
      value = [], 
  onChange, 
  maxFiles = 50, 
  maxSize = 100 * 1024 * 1024, // 100MB default
    accept = {
      'image/*': ['.png', '.jpg', '.jpeg', '.gif', '.webp'],
      'application/pdf': ['.pdf'],
      'application/msword': ['.doc'],
      'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['.docx'],
      'text/plain': ['.txt'],
    },
    disabled = false,
    className,
    placeholder = "Drop files here or click to upload"
  }, ref) => {
    const [uploadingFiles, setUploadingFiles] = React.useState<UploadingFile[]>([]);
    const [isDragActive, setIsDragActive] = React.useState(false);

    const onDrop = useCallback(async (acceptedFiles: File[]) => {
      if (disabled) return;
      
      const newFiles = acceptedFiles.slice(0, maxFiles - value.length);
      const initialUploadingFiles = newFiles.map(file => ({
        file,
        progress: 0
      }));
      
      setUploadingFiles(prev => [...prev, ...initialUploadingFiles]);

      // Upload files using local API
      for (const uploadingFile of initialUploadingFiles) {
        try {
          const formData = new FormData();
          formData.append('file', uploadingFile.file);
          
          // Create XMLHttpRequest for progress tracking
          const uploadPromise = new Promise<string>((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            
            xhr.upload.addEventListener('progress', (e) => {
              if (e.lengthComputable) {
                const progress = (e.loaded / e.total) * 100;
                setUploadingFiles(prev => 
                  prev.map(f => 
                    f.file === uploadingFile.file 
                      ? { ...f, progress: Math.min(progress, 100) }
                      : f
                  )
                );
              }
            });

            xhr.addEventListener('load', () => {
              if (xhr.status === 200) {
                const response = JSON.parse(xhr.responseText);
                resolve(response.url);
              } else {
                reject(new Error('Upload failed'));
              }
            });

            xhr.addEventListener('error', () => {
              reject(new Error('Upload failed'));
            });

            xhr.open('POST', '/api/upload');
            xhr.send(formData);
          });

          const fileUrl = await uploadPromise;
          
          setUploadingFiles(prev => 
            prev.map(f => 
              f.file === uploadingFile.file 
                ? { ...f, progress: 100, url: fileUrl }
                : f
            )
          );
          
          // Add to value array
          onChange([...value, fileUrl]);
          
        } catch (error) {
          setUploadingFiles(prev => 
            prev.map(f => 
              f.file === uploadingFile.file 
                ? { ...f, error: 'Upload failed' }
                : f
            )
          );
        }
      }
      
      // Clean up completed uploads after a delay
      setTimeout(() => {
        setUploadingFiles(prev => prev.filter(f => f.progress < 100 && !f.error));
      }, 2000);
    }, [value, onChange, maxFiles, disabled]);

    const { getRootProps, getInputProps, isDragActive: dropzoneIsDragActive } = useDropzone({
      onDrop,
      accept,
      maxSize,
      disabled,
      multiple: maxFiles > 1,
      onDragEnter: () => setIsDragActive(true),
      onDragLeave: () => setIsDragActive(false),
    });

    const removeFile = (fileUrl: string) => {
      onChange(value.filter(url => url !== fileUrl));
    };

    const getFileIcon = (fileName: string) => {
      const extension = fileName.split('.').pop()?.toLowerCase();
      if (['png', 'jpg', 'jpeg', 'gif', 'webp'].includes(extension || '')) {
        return <Image className="h-4 w-4" />;
      } else if (extension === 'pdf') {
        return <FileText className="h-4 w-4" />;
      }
      return <File className="h-4 w-4" />;
    };

    const getFileName = (url: string) => {
      return url.split('/').pop() || 'Unknown file';
    };

    const canAddMore = value.length + uploadingFiles.length < maxFiles;

    return (
      <div ref={ref} className={cn("space-y-2", className)}>
        {/* Upload Area */}
        {canAddMore && (
          <div
            {...getRootProps()}
            className={cn(
              "border-2 border-dashed rounded-lg p-6 text-center cursor-pointer transition-colors",
              isDragActive || dropzoneIsDragActive
                ? "border-primary bg-primary/5"
                : "border-gray-300 hover:border-gray-400",
              disabled && "cursor-not-allowed opacity-50"
            )}
          >
            <input {...getInputProps()} />
            <Upload className="mx-auto h-8 w-8 text-gray-400 mb-2" />
            <p className="text-sm text-gray-600">
              {isDragActive || dropzoneIsDragActive ? "Drop files here..." : placeholder}
            </p>
            {/* <p className="text-xs text-gray-400 mt-1">
              Max {maxFiles} files, up to {Math.round(maxSize / (1024 * 1024))}MB each
            </p> */}
          </div>
        )}

        {/* Uploading Files */}
        {uploadingFiles.map((uploadingFile, index) => (
          <div key={index} className="flex items-center gap-2 p-2 bg-gray-50 rounded-lg">
            {getFileIcon(uploadingFile.file.name)}
            <div className="flex-1 min-w-0">
              <p className="text-sm font-medium truncate">{uploadingFile.file.name}</p>
              {uploadingFile.error ? (
                <p className="text-xs text-red-500">{uploadingFile.error}</p>
              ) : (
                <Progress value={uploadingFile.progress} className="h-1 mt-1" />
              )}
            </div>
            <Loader2 className="h-4 w-4 animate-spin text-gray-400" />
          </div>
        ))}

        {/* Uploaded Files */}
        {value.map((fileUrl, index) => (
          <div key={index} className="flex items-center gap-2 p-2 bg-gray-50 rounded-lg">
            {getFileIcon(fileUrl)}
            <div className="flex-1 min-w-0">
              <p className="text-sm font-medium truncate">{getFileName(fileUrl)}</p>
              <p className="text-xs text-gray-500">Uploaded</p>
            </div>
            <Button
              type="button"
              variant="ghost"
              size="sm"
              onClick={() => removeFile(fileUrl)}
              disabled={disabled}
              className="h-6 w-6 p-0"
            >
              <X className="h-3 w-3" />
            </Button>
          </div>
        ))}

        {/* File Count */}
        {value.length > 0 && (
          <p className="text-xs text-gray-500 text-center">
            {value.length} of {maxFiles} files uploaded
          </p>
        )}
      </div>
    );
  }
);

FileUpload.displayName = "FileUpload";

export { FileUpload }; 