'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,
  Eye,
  Download,
  FileText,
  Languages,
  Play,
  X,
} from 'lucide-react'
import { cn, formatFileSize } from '@/lib/utils'
import { toast } from 'sonner'
import { FilePreview, isOfficeFile } from '@/components/shared/file-viewer'

function getMimeLabel(mime: string): string {
  if (mime === 'application/pdf') return 'PDF'
  if (mime.startsWith('image/')) return 'Images'
  if (mime === 'video/mp4') return 'MP4'
  if (mime === 'video/quicktime') return 'MOV'
  if (mime === 'video/webm') return 'WebM'
  if (mime.startsWith('video/')) return 'Video'
  if (mime.includes('wordprocessingml') || mime === 'application/msword') return 'Word'
  if (mime.includes('spreadsheetml')) return 'Excel'
  if (mime.includes('presentationml') || mime === 'application/vnd.ms-powerpoint') 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
  bucket?: string
  objectKey?: string
  pageCount?: number | null
  detectedLang?: string | null
  analyzedAt?: string | Date | null
}

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

function ViewFileButton({ bucket, objectKey }: { bucket: string; objectKey: string }) {
  const { data } = trpc.file.getDownloadUrl.useQuery(
    { bucket, objectKey, forDownload: false },
    { staleTime: 10 * 60 * 1000 }
  )
  const href = typeof data === 'string' ? data : data?.url
  return (
    <Button variant="ghost" size="sm" className="h-6 px-2 text-xs gap-1" asChild disabled={!href}>
      <a href={href || '#'} target="_blank" rel="noopener noreferrer">
        <Eye className="h-3 w-3" /> View
      </a>
    </Button>
  )
}

function DownloadFileButton({ bucket, objectKey, fileName }: { bucket: string; objectKey: string; fileName: string }) {
  const { data } = trpc.file.getDownloadUrl.useQuery(
    { bucket, objectKey, forDownload: true, fileName },
    { staleTime: 10 * 60 * 1000 }
  )
  const href = typeof data === 'string' ? data : data?.url
  return (
    <Button variant="ghost" size="sm" className="h-6 px-2 text-xs gap-1" asChild disabled={!href}>
      <a href={href || '#'} download={fileName}>
        <Download className="h-3 w-3" /> Download
      </a>
    </Button>
  )
}

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 [showPreview, setShowPreview] = 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 and auto-retry
        const maxRetries = 3
        for (let attempt = 1; attempt <= maxRetries; attempt++) {
          try {
            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('Network error during upload'))
              )
              xhr.addEventListener('abort', () =>
                reject(new Error('Upload was aborted'))
              )
              xhr.open('PUT', url)
              xhr.setRequestHeader('Content-Type', file.type)
              xhr.send(file)
            })
            break // Success — exit retry loop
          } catch (uploadErr) {
            if (attempt < maxRetries) {
              const delay = attempt * 2000
              toast.info(`Upload interrupted, retrying... (${attempt}/${maxRetries})`)
              setProgress(0)
              await new Promise((r) => setTimeout(r, delay))
            } else {
              throw uploadErr
            }
          }
        }

        // 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])

  // Fetch preview URL only when preview is toggled on
  const { data: previewUrlData, isLoading: isLoadingPreview } = trpc.file.getDownloadUrl.useQuery(
    { bucket: existingFile?.bucket || '', objectKey: existingFile?.objectKey || '', forDownload: false, purpose: 'preview' as const },
    { enabled: showPreview && !!existingFile?.bucket && !!existingFile?.objectKey, staleTime: 10 * 60 * 1000 }
  )
  const previewUrl = typeof previewUrlData === 'string' ? previewUrlData : previewUrlData?.url

  const canPreview = existingFile
    ? existingFile.mimeType.startsWith('video/') ||
      existingFile.mimeType === 'application/pdf' ||
      existingFile.mimeType.startsWith('image/') ||
      isOfficeFile(existingFile.mimeType, existingFile.fileName)
    : false

  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">
            {[...new Set(requirement.acceptedMimeTypes.map(getMimeLabel))].map((label) => (
              <Badge key={label} variant="outline" className="text-xs">
                {label}
              </Badge>
            ))}
            {requirement.maxSizeMB && (
              <Badge variant="outline" className="text-xs">
                Max {requirement.maxSizeMB}MB
              </Badge>
            )}
          </div>

          {existingFile && (
            <div className="ml-6 space-y-1.5">
              <div className="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>
                {existingFile.pageCount != null && (
                  <span className="flex items-center gap-0.5">
                    <FileText className="h-3 w-3" />
                    {existingFile.pageCount} page{existingFile.pageCount !== 1 ? 's' : ''}
                  </span>
                )}
                {existingFile.detectedLang && existingFile.detectedLang !== 'und' && (
                  <span className="flex items-center gap-0.5">
                    <Languages className="h-3 w-3" />
                    {existingFile.detectedLang.toUpperCase()}
                  </span>
                )}
              </div>
              {existingFile.bucket && existingFile.objectKey && (
                <div className="flex items-center gap-1.5">
                  {canPreview && (
                    <Button
                      variant="ghost"
                      size="sm"
                      className="h-6 px-2 text-xs gap-1"
                      onClick={() => setShowPreview(!showPreview)}
                    >
                      {showPreview ? (
                        <><X className="h-3 w-3" /> Close Preview</>
                      ) : (
                        <><Play className="h-3 w-3" /> Preview</>
                      )}
                    </Button>
                  )}
                  <ViewFileButton bucket={existingFile.bucket} objectKey={existingFile.objectKey} />
                  <DownloadFileButton bucket={existingFile.bucket} objectKey={existingFile.objectKey} fileName={existingFile.fileName} />
                </div>
              )}
            </div>
          )}

          {/* Inline preview panel */}
          {showPreview && existingFile && (
            <div className="ml-6 mt-2 rounded-lg border bg-muted/50 overflow-hidden">
              {isLoadingPreview ? (
                <div className="flex items-center justify-center py-8">
                  <Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
                </div>
              ) : previewUrl ? (
                <FilePreview
                  file={{ mimeType: existingFile.mimeType, fileName: existingFile.fileName }}
                  url={previewUrl}
                />
              ) : (
                <div className="flex items-center justify-center py-8 text-muted-foreground">
                  <AlertCircle className="mr-2 h-4 w-4" />
                  Failed to load preview
                </div>
              )}
            </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,
                    bucket: (existing as { bucket?: string }).bucket,
                    objectKey: (existing as { objectKey?: string }).objectKey,
                    pageCount: (existing as { pageCount?: number | null }).pageCount,
                    detectedLang: (existing as { detectedLang?: string | null }).detectedLang,
                    analyzedAt: (existing as { analyzedAt?: string | null }).analyzedAt,
                  }
                : null
            }
            projectId={projectId}
            roundId={roundId}
            onFileChange={handleFileChange}
            disabled={disabled}
          />
        )
      })}
    </div>
  )
}
