"use client"

import React, { useCallback, useState, useId } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { Button } from './button'
import { Progress } from './progress'
import { Badge } from './badge'
import { cn } from '../../lib/utils'
import { 
  Upload, 
  X, 
  File, 
  Image as ImageIcon, 
  Video, 
  Music, 
  FileText,
  CheckCircle,
  AlertCircle,
  Loader2
} from 'lucide-react'

export interface FileUploadProps {
  accept?: string
  multiple?: boolean
  maxSize?: number // in bytes
  maxFiles?: number
  disabled?: boolean
  className?: string
  onUpload?: (files: File[]) => Promise<void>
  onRemove?: (fileId: string) => void
  children?: React.ReactNode
}

interface UploadedFile {
  id: string
  file: File
  progress: number
  status: 'uploading' | 'success' | 'error'
  preview?: string
}

const getFileIcon = (type: string) => {
  if (type.startsWith('image/')) return <ImageIcon className="h-4 w-4" />
  if (type.startsWith('video/')) return <Video className="h-4 w-4" />
  if (type.startsWith('audio/')) return <Music className="h-4 w-4" />
  if (type.includes('text') || type.includes('document')) return <FileText className="h-4 w-4" />
  return <File className="h-4 w-4" />
}

const formatFileSize = (bytes: number): string => {
  if (bytes === 0) return '0 Bytes'
  const k = 1024
  const sizes = ['Bytes', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

const FileItem = ({ 
  uploadedFile, 
  onRemove 
}: { 
  uploadedFile: UploadedFile
  onRemove: (id: string) => void 
}) => {
  const { id, file, progress, status, preview } = uploadedFile

  return (
    <motion.div
      initial={{ opacity: 0, y: 10 }}
      animate={{ opacity: 1, y: 0 }}
      exit={{ opacity: 0, y: -10 }}
      className="flex items-center space-x-3 p-3 border rounded-lg bg-background"
    >
      {/* File Preview/Icon */}
      <div className="flex-shrink-0">
        {preview ? (
          <img 
            src={preview} 
            alt={file.name}
            className="h-10 w-10 object-cover rounded"
          />
        ) : (
          <div className="h-10 w-10 rounded bg-muted flex items-center justify-center">
            {getFileIcon(file.type)}
          </div>
        )}
      </div>

      {/* File Info */}
      <div className="flex-1 min-w-0">
        <div className="flex items-center justify-between">
          <p className="text-sm font-medium truncate">{file.name}</p>
          <Button
            variant="ghost"
            size="sm"
            className="h-6 w-6 p-0"
            onClick={() => onRemove(id)}
          >
            <X className="h-3 w-3" />
          </Button>
        </div>
        
        <div className="flex items-center space-x-2 mt-1">
          <p className="text-xs text-muted-foreground">{formatFileSize(file.size)}</p>
          
          {/* Status Badge */}
          {status === 'uploading' && (
            <Badge variant="secondary" className="h-5">
              <Loader2 className="h-3 w-3 mr-1 animate-spin" />
              Uploading
            </Badge>
          )}
          {status === 'success' && (
            <Badge variant="success" className="h-5">
              <CheckCircle className="h-3 w-3 mr-1" />
              Done
            </Badge>
          )}
          {status === 'error' && (
            <Badge variant="destructive" className="h-5">
              <AlertCircle className="h-3 w-3 mr-1" />
              Error
            </Badge>
          )}
        </div>

        {/* Progress Bar */}
        {status === 'uploading' && (
          <div className="mt-2">
            <Progress value={progress} className="h-1" />
          </div>
        )}
      </div>
    </motion.div>
  )
}

export const FileUpload = React.forwardRef<HTMLDivElement, FileUploadProps>(
  ({ 
    accept = "*",
    multiple = true,
    maxSize = 10 * 1024 * 1024, // 10MB
    maxFiles = 5,
    disabled = false,
    className,
    onUpload,
    onRemove,
    children,
    ...props 
  }, ref) => {
    const [uploadedFiles, setUploadedFiles] = useState<UploadedFile[]>([])
    const [isDragOver, setIsDragOver] = useState(false)
    const [error, setError] = useState<string | null>(null)

    const validateFile = (file: File): string | null => {
      if (file.size > maxSize) {
        return `File size exceeds ${formatFileSize(maxSize)}`
      }

      if (accept !== "*" && !accept.split(',').some(type => {
        const cleanType = type.trim()
        if (cleanType.includes('*')) {
          return file.type.startsWith(cleanType.replace('*', ''))
        }
        return file.type === cleanType
      })) {
        return `File type not supported`
      }

      return null
    }

    const processFiles = useCallback(async (files: FileList | File[]) => {
      const fileArray = Array.from(files)
      setError(null)

      // Check total file count
      if (uploadedFiles.length + fileArray.length > maxFiles) {
        setError(`Maximum ${maxFiles} files allowed`)
        return
      }

      const validFiles: File[] = []
      const errors: string[] = []

      // Validate each file
      fileArray.forEach(file => {
        const validationError = validateFile(file)
        if (validationError) {
          errors.push(`${file.name}: ${validationError}`)
        } else {
          validFiles.push(file)
        }
      })

      if (errors.length > 0) {
        setError(errors.join(', '))
        return
      }

      // Create uploaded file entries
      const newUploadedFiles: UploadedFile[] = validFiles.map((file, index) => ({
        id: `${Date.now()}-${index}-${file.name.replace(/[^a-zA-Z0-9]/g, '')}`,
        file,
        progress: 0,
        status: 'uploading' as const,
        preview: file.type.startsWith('image/') ? URL.createObjectURL(file) : undefined
      }))

      setUploadedFiles(prev => [...prev, ...newUploadedFiles])

      // Simulate upload progress
      for (const uploadedFile of newUploadedFiles) {
        let progress = 0
        const interval = setInterval(() => {
          progress += 15 + (uploadedFile.file.size % 10) // Deterministic progress based on file size
          if (progress >= 100) {
            progress = 100
            clearInterval(interval)
            
            setUploadedFiles(prev => 
              prev.map(f => 
                f.id === uploadedFile.id 
                  ? { ...f, progress: 100, status: 'success' as const }
                  : f
              )
            )
          } else {
            setUploadedFiles(prev => 
              prev.map(f => 
                f.id === uploadedFile.id 
                  ? { ...f, progress }
                  : f
              )
            )
          }
        }, 200)
      }

      // Call onUpload if provided
      if (onUpload) {
        try {
          await onUpload(validFiles)
        } catch (error) {
          console.error('Upload failed:', error)
          setUploadedFiles(prev => 
            prev.map(f => 
              newUploadedFiles.some(nf => nf.id === f.id)
                ? { ...f, status: 'error' as const }
                : f
            )
          )
        }
      }
    }, [uploadedFiles.length, maxFiles, maxSize, accept, onUpload])

    const handleDrop = useCallback((e: React.DragEvent) => {
      e.preventDefault()
      setIsDragOver(false)
      
      if (disabled) return
      
      const files = e.dataTransfer.files
      if (files.length > 0) {
        processFiles(files)
      }
    }, [processFiles, disabled])

    const handleDragOver = useCallback((e: React.DragEvent) => {
      e.preventDefault()
      if (!disabled) {
        setIsDragOver(true)
      }
    }, [disabled])

    const handleDragLeave = useCallback((e: React.DragEvent) => {
      e.preventDefault()
      setIsDragOver(false)
    }, [])

    const handleFileSelect = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
      const files = e.target.files
      if (files && files.length > 0) {
        processFiles(files)
      }
      // Reset input value
      e.target.value = ''
    }, [processFiles])

    const removeFile = useCallback((fileId: string) => {
      setUploadedFiles(prev => {
        const fileToRemove = prev.find(f => f.id === fileId)
        if (fileToRemove?.preview) {
          URL.revokeObjectURL(fileToRemove.preview)
        }
        return prev.filter(f => f.id !== fileId)
      })
      
      if (onRemove) {
        onRemove(fileId)
      }
    }, [onRemove])

    return (
      <div ref={ref} className={cn("moonui-theme", "space-y-4", className)} {...props}>
        {/* Upload Area */}
        <motion.div
          className={cn(
            "relative border-2 border-dashed rounded-lg p-8 text-center transition-colors",
            isDragOver && "border-primary bg-primary/5",
            disabled && "opacity-50 cursor-not-allowed",
            !disabled && "hover:border-primary/50 cursor-pointer"
          )}
          onDrop={handleDrop}
          onDragOver={handleDragOver}
          onDragLeave={handleDragLeave}
          animate={{
            scale: isDragOver ? 1.02 : 1,
            borderColor: isDragOver ? "hsl(var(--primary))" : "hsl(var(--border))"
          }}
        >
          <input
            type="file"
            accept={accept}
            multiple={multiple}
            disabled={disabled}
            onChange={handleFileSelect}
            className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
          />
          
          {children || (
            <div className="space-y-4">
              <div className="mx-auto h-12 w-12 text-muted-foreground">
                <Upload className="h-full w-full" />
              </div>
              <div>
                <p className="text-lg font-medium">
                  {isDragOver ? 'Drop files here' : 'Upload files'}
                </p>
                <p className="text-sm text-muted-foreground">
                  Drag & drop files here, or click to select
                </p>
                <p className="text-xs text-muted-foreground mt-2">
                  Max {maxFiles} files, {formatFileSize(maxSize)} each
                </p>
              </div>
              <Button variant="outline" disabled={disabled}>
                Select Files
              </Button>
            </div>
          )}
        </motion.div>

        {/* Error Message */}
        <AnimatePresence>
          {error && (
            <motion.div
              initial={{ opacity: 0, y: -10 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -10 }}
              className="flex items-center space-x-2 text-sm text-destructive"
            >
              <AlertCircle className="h-4 w-4" />
              <span>{error}</span>
            </motion.div>
          )}
        </AnimatePresence>

        {/* Uploaded Files */}
        <AnimatePresence>
          {uploadedFiles.length > 0 && (
            <motion.div
              initial={{ opacity: 0, height: 0 }}
              animate={{ opacity: 1, height: 'auto' }}
              exit={{ opacity: 0, height: 0 }}
              className="space-y-2"
            >
              <h4 className="text-sm font-medium">
                Uploaded Files ({uploadedFiles.length})
              </h4>
              <div className="space-y-2">
                <AnimatePresence>
                  {uploadedFiles.map(uploadedFile => (
                    <FileItem
                      key={uploadedFile.id}
                      uploadedFile={uploadedFile}
                      onRemove={removeFile}
                    />
                  ))}
                </AnimatePresence>
              </div>
            </motion.div>
          )}
        </AnimatePresence>
      </div>
    )
  }
)

FileUpload.displayName = "FileUpload"