'use client'

import { useState, useCallback, useRef } from 'react'
import { trpc } from '@/lib/trpc/client'
import { Button } from '@/components/ui/button'
import { Progress } from '@/components/ui/progress'
import { Badge } from '@/components/ui/badge'
import {
  Upload,
  FileIcon,
  CheckCircle2,
  AlertCircle,
  Loader2,
  Trash2,
  RefreshCw,
} from 'lucide-react'
import { cn, formatFileSize } from '@/lib/utils'
import { toast } from 'sonner'

function getMimeLabel(mime: string): string {
  if (mime === 'application/pdf') return 'PDF'
  if (mime.startsWith('image/')) return 'Images'
  if (mime.startsWith('video/')) return 'Video'
  if (mime.includes('wordprocessingml')) return 'Word'
  if (mime.includes('spreadsheetml')) return 'Excel'
  if (mime.includes('presentationml')) return 'PowerPoint'
  if (mime.endsWith('/*')) return mime.replace('/*', '')
  return mime
}

interface FileRequirement {
  id: string
  name: string
  description?: string | null
  acceptedMimeTypes: string[]
  maxSizeMB?: number | null
  isRequired: boolean
}

interface UploadedFile {
  id: string
  fileName: string
  mimeType: string
  size: number
  createdAt: string | Date
  requirementId?: string | null
}

interface RequirementUploadSlotProps {
  requirement: FileRequirement
  existingFile?: UploadedFile | null
  projectId: string
  roundId: string
  onFileChange?: () => void
  disabled?: boolean
}

export function RequirementUploadSlot({
  requirement,
  existingFile,
  projectId,
  roundId,
  onFileChange,
  disabled = false,
}: RequirementUploadSlotProps) {
  const [uploading, setUploading] = useState(false)
  const [progress, setProgress] = useState(0)
  const [deleting, setDeleting] = useState(false)
  const fileInputRef = useRef<HTMLInputElement>(null)

  const getUploadUrl = trpc.applicant.getUploadUrl.useMutation()
  const saveFileMetadata = trpc.applicant.saveFileMetadata.useMutation()
  const deleteFile = trpc.applicant.deleteFile.useMutation()

  const acceptsMime = useCallback(
    (mimeType: string) => {
      if (requirement.acceptedMimeTypes.length === 0) return true
      return requirement.acceptedMimeTypes.some((pattern) => {
        if (pattern.endsWith('/*')) {
          return mimeType.startsWith(pattern.replace('/*', '/'))
        }
        return mimeType === pattern
      })
    },
    [requirement.acceptedMimeTypes]
  )

  const handleFileSelect = useCallback(
    async (e: React.ChangeEvent<HTMLInputElement>) => {
      const file = e.target.files?.[0]
      if (!file) return

      // Reset input
      if (fileInputRef.current) fileInputRef.current.value = ''

      // Validate mime type
      if (!acceptsMime(file.type)) {
        toast.error(`File type ${file.type} is not accepted for this requirement`)
        return
      }

      // Validate size
      if (requirement.maxSizeMB && file.size > requirement.maxSizeMB * 1024 * 1024) {
        toast.error(`File exceeds maximum size of ${requirement.maxSizeMB}MB`)
        return
      }

      setUploading(true)
      setProgress(0)

      try {
        // Get presigned URL
        const { url, bucket, objectKey, isLate, roundId: uploadRoundId } =
          await getUploadUrl.mutateAsync({
            projectId,
            fileName: file.name,
            mimeType: file.type,
            fileType: 'OTHER',
            roundId,
            requirementId: requirement.id,
          })

        // Upload file with progress tracking
        await new Promise<void>((resolve, reject) => {
          const xhr = new XMLHttpRequest()
          xhr.upload.addEventListener('progress', (event) => {
            if (event.lengthComputable) {
              setProgress(Math.round((event.loaded / event.total) * 100))
            }
          })
          xhr.addEventListener('load', () => {
            if (xhr.status >= 200 && xhr.status < 300) {
              resolve()
            } else {
              reject(new Error(`Upload failed with status ${xhr.status}`))
            }
          })
          xhr.addEventListener('error', () => reject(new Error('Upload failed')))
          xhr.open('PUT', url)
          xhr.setRequestHeader('Content-Type', file.type)
          xhr.send(file)
        })

        // Save metadata
        await saveFileMetadata.mutateAsync({
          projectId,
          fileName: file.name,
          mimeType: file.type,
          size: file.size,
          fileType: 'OTHER',
          bucket,
          objectKey,
          roundId: uploadRoundId || roundId,
          isLate: isLate || false,
          requirementId: requirement.id,
        })

        toast.success(`${requirement.name} uploaded successfully`)
        onFileChange?.()
      } catch (err) {
        toast.error(err instanceof Error ? err.message : 'Upload failed')
      } finally {
        setUploading(false)
        setProgress(0)
      }
    },
    [projectId, roundId, requirement, acceptsMime, getUploadUrl, saveFileMetadata, onFileChange]
  )

  const handleDelete = useCallback(async () => {
    if (!existingFile) return
    setDeleting(true)
    try {
      await deleteFile.mutateAsync({ fileId: existingFile.id })
      toast.success('File deleted')
      onFileChange?.()
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'Delete failed')
    } finally {
      setDeleting(false)
    }
  }, [existingFile, deleteFile, onFileChange])

  const isFulfilled = !!existingFile
  const statusColor = isFulfilled
    ? 'border-green-200 bg-green-50 dark:border-green-900 dark:bg-green-950'
    : requirement.isRequired
      ? 'border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950'
      : 'border-muted'

  // Build accept string for file input
  const acceptStr =
    requirement.acceptedMimeTypes.length > 0
      ? requirement.acceptedMimeTypes.join(',')
      : undefined

  return (
    <div className={cn('rounded-lg border p-4 transition-colors', statusColor)}>
      <div className="flex items-start justify-between gap-3">
        <div className="flex-1 min-w-0">
          <div className="flex items-center gap-2 mb-1">
            {isFulfilled ? (
              <CheckCircle2 className="h-4 w-4 text-green-600 shrink-0" />
            ) : requirement.isRequired ? (
              <AlertCircle className="h-4 w-4 text-red-500 shrink-0" />
            ) : (
              <FileIcon className="h-4 w-4 text-muted-foreground shrink-0" />
            )}
            <span className="font-medium text-sm">{requirement.name}</span>
            <Badge
              variant={requirement.isRequired ? 'destructive' : 'secondary'}
              className="text-xs shrink-0"
            >
              {requirement.isRequired ? 'Required' : 'Optional'}
            </Badge>
          </div>

          {requirement.description && (
            <p className="text-xs text-muted-foreground ml-6 mb-2">
              {requirement.description}
            </p>
          )}

          <div className="flex flex-wrap gap-1 ml-6 mb-2">
            {requirement.acceptedMimeTypes.map((mime) => (
              <Badge key={mime} variant="outline" className="text-xs">
                {getMimeLabel(mime)}
              </Badge>
            ))}
            {requirement.maxSizeMB && (
              <Badge variant="outline" className="text-xs">
                Max {requirement.maxSizeMB}MB
              </Badge>
            )}
          </div>

          {existingFile && (
            <div className="ml-6 flex items-center gap-2 text-xs text-muted-foreground">
              <FileIcon className="h-3 w-3" />
              <span className="truncate">{existingFile.fileName}</span>
              <span>({formatFileSize(existingFile.size)})</span>
            </div>
          )}

          {uploading && (
            <div className="ml-6 mt-2">
              <Progress value={progress} className="h-1.5" />
              <p className="text-xs text-muted-foreground mt-1">Uploading... {progress}%</p>
            </div>
          )}
        </div>

        {!disabled && (
          <div className="flex items-center gap-1 shrink-0">
            {existingFile ? (
              <>
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => fileInputRef.current?.click()}
                  disabled={uploading}
                >
                  <RefreshCw className="mr-1 h-3 w-3" />
                  Replace
                </Button>
                <Button
                  variant="ghost"
                  size="icon"
                  className="h-8 w-8 text-destructive hover:text-destructive"
                  onClick={handleDelete}
                  disabled={deleting}
                >
                  {deleting ? (
                    <Loader2 className="h-4 w-4 animate-spin" />
                  ) : (
                    <Trash2 className="h-4 w-4" />
                  )}
                </Button>
              </>
            ) : (
              <Button
                variant="outline"
                size="sm"
                onClick={() => fileInputRef.current?.click()}
                disabled={uploading}
              >
                {uploading ? (
                  <Loader2 className="mr-1 h-3 w-3 animate-spin" />
                ) : (
                  <Upload className="mr-1 h-3 w-3" />
                )}
                Upload
              </Button>
            )}
          </div>
        )}
      </div>

      <input
        ref={fileInputRef}
        type="file"
        className="hidden"
        accept={acceptStr}
        onChange={handleFileSelect}
      />
    </div>
  )
}

interface RequirementUploadListProps {
  projectId: string
  roundId: string
  disabled?: boolean
}

export function RequirementUploadList({ projectId, roundId, disabled }: RequirementUploadListProps) {
  const utils = trpc.useUtils()

  const { data: requirements = [] } = trpc.file.listRequirements.useQuery({
    roundId,
  })
  const { data: files = [] } = trpc.file.listByProject.useQuery({ projectId, roundId })

  if (requirements.length === 0) return null

  const handleFileChange = () => {
    utils.file.listByProject.invalidate({ projectId, roundId })
  }

  return (
    <div className="space-y-3">
      <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wide">
        Required Documents
      </h3>
      {requirements.map((req) => {
        const existing = files.find(
          (f) => (f as { requirementId?: string | null }).requirementId === req.id
        )
        return (
          <RequirementUploadSlot
            key={req.id}
            requirement={req}
            existingFile={
              existing
                ? {
                    id: existing.id,
                    fileName: existing.fileName,
                    mimeType: existing.mimeType,
                    size: existing.size,
                    createdAt: existing.createdAt,
                    requirementId: (existing as { requirementId?: string | null }).requirementId,
                  }
                : null
            }
            projectId={projectId}
            roundId={roundId}
            onFileChange={handleFileChange}
            disabled={disabled}
          />
        )
      })}
    </div>
  )
}
