'use client'

import { useState, useCallback, useRef, useEffect, useMemo } from 'react'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import { trpc } from '@/lib/trpc/client'
import { toast } from 'sonner'
import {
  Card,
  CardContent,
  CardHeader,
  CardTitle,
} from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Progress } from '@/components/ui/progress'
import { Skeleton } from '@/components/ui/skeleton'
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@/components/ui/table'
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select'
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog'
import {
  ArrowLeft,
  CheckCircle2,
  Upload,
  Search,
  X,
  Loader2,
  FileUp,
  AlertCircle,
  ExternalLink,
  Trash2,
} from 'lucide-react'
import { cn, formatFileSize } from '@/lib/utils'
import { Pagination } from '@/components/shared/pagination'

type UploadState = {
  progress: number
  status: 'uploading' | 'complete' | 'error'
  error?: string
}

// Key: `${projectId}:${requirementId}`
type UploadMap = Record<string, UploadState>

export default function BulkUploadPage() {
  const router = useRouter()
  const [roundId, setRoundId] = useState('')
  const [search, setSearch] = useState('')
  const [debouncedSearch, setDebouncedSearch] = useState('')
  const [statusFilter, setStatusFilter] = useState<'all' | 'missing' | 'complete'>('all')
  const [page, setPage] = useState(1)
  const [perPage, setPerPage] = useState(50)
  const [uploads, setUploads] = useState<UploadMap>({})

  // Bulk dialog
  const [bulkProject, setBulkProject] = useState<{
    id: string
    title: string
    requirements: Array<{
      requirementId: string
      label: string
      mimeTypes: string[]
      required: boolean
      file: { id: string; fileName: string; bucket: string; objectKey: string } | null
    }>
  } | null>(null)
  const [bulkFiles, setBulkFiles] = useState<Record<string, File | null>>({})

  const fileInputRefs = useRef<Record<string, HTMLInputElement | null>>({})
  const utils = trpc.useUtils()

  // Debounce search
  const searchTimer = useRef<ReturnType<typeof setTimeout>>(undefined)
  const handleSearchChange = useCallback((value: string) => {
    setSearch(value)
    clearTimeout(searchTimer.current)
    searchTimer.current = setTimeout(() => {
      setDebouncedSearch(value)
      setPage(1)
    }, 300)
  }, [])

  // Queries
  const { data: rounds, isLoading: roundsLoading } = trpc.file.listRoundsForBulkUpload.useQuery()

  const { data, isLoading, refetch } = trpc.file.listProjectsByRoundRequirements.useQuery(
    {
      roundId,
      search: debouncedSearch || undefined,
      status: statusFilter,
      page,
      pageSize: perPage,
    },
    { enabled: !!roundId }
  )

  // Collect all files from current data for existence verification
  const filesToVerify = useMemo(() => {
    if (!data?.projects) return []
    const files: { bucket: string; objectKey: string }[] = []
    for (const row of data.projects) {
      for (const req of row.requirements) {
        if (req.file?.bucket && req.file?.objectKey) {
          files.push({ bucket: req.file.bucket, objectKey: req.file.objectKey })
        }
      }
    }
    return files
  }, [data])

  // Verify files actually exist in storage
  const { data: fileExistence } = trpc.file.verifyFilesExist.useQuery(
    { files: filesToVerify },
    { enabled: filesToVerify.length > 0, staleTime: 30_000 }
  )

  // Track which files are missing from storage (objectKey → true means missing)
  const missingFiles = useMemo(() => {
    if (!fileExistence) return new Set<string>()
    const missing = new Set<string>()
    for (const [key, exists] of Object.entries(fileExistence)) {
      if (!exists) missing.add(key)
    }
    return missing
  }, [fileExistence])

  // Open file in new tab via presigned URL
  const handleViewFile = useCallback(
    async (bucket: string, objectKey: string) => {
      try {
        const { url } = await utils.file.getDownloadUrl.fetch({ bucket, objectKey, purpose: 'open' as const })
        window.open(url, '_blank')
      } catch {
        toast.error('Failed to open file. It may have been deleted from storage.')
        refetch()
      }
    },
    [utils, refetch]
  )

  // Delete a file
  const deleteMutation = trpc.file.delete.useMutation({
    onSuccess: () => {
      toast.success('File removed')
      refetch()
    },
    onError: (err) => {
      toast.error(`Failed to remove file: ${err.message}`)
    },
  })

  const handleDeleteFile = useCallback(
    (fileId: string) => {
      if (confirm('Remove this uploaded file?')) {
        deleteMutation.mutate({ id: fileId })
      }
    },
    [deleteMutation]
  )

  const uploadMutation = trpc.file.adminUploadForRoundRequirement.useMutation()

  // Upload a single file for a project requirement
  const uploadFileForRequirement = useCallback(
    async (
      projectId: string,
      requirementId: string,
      file: File,
      targetRoundId: string
    ) => {
      const key = `${projectId}:${requirementId}`
      setUploads((prev) => ({
        ...prev,
        [key]: { progress: 0, status: 'uploading' },
      }))

      try {
        const { uploadUrl } = await uploadMutation.mutateAsync({
          projectId,
          fileName: file.name,
          mimeType: file.type || 'application/octet-stream',
          size: file.size,
          roundId: targetRoundId,
          requirementId,
        })

        // XHR upload with progress
        await new Promise<void>((resolve, reject) => {
          const xhr = new XMLHttpRequest()
          xhr.upload.addEventListener('progress', (event) => {
            if (event.lengthComputable) {
              const progress = Math.round((event.loaded / event.total) * 100)
              setUploads((prev) => ({
                ...prev,
                [key]: { progress, status: 'uploading' },
              }))
            }
          })
          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')))
          xhr.open('PUT', uploadUrl)
          xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream')
          xhr.send(file)
        })

        setUploads((prev) => ({
          ...prev,
          [key]: { progress: 100, status: 'complete' },
        }))

        // Refetch data to show updated status
        refetch()
      } catch (error) {
        const msg = error instanceof Error ? error.message : 'Upload failed'
        setUploads((prev) => ({
          ...prev,
          [key]: { progress: 0, status: 'error', error: msg },
        }))
        toast.error(`Upload failed: ${msg}`)
      }
    },
    [uploadMutation, refetch]
  )

  // Handle single cell file pick
  const handleCellUpload = useCallback(
    (projectId: string, requirementId: string, mimeTypes: string[]) => {
      const input = document.createElement('input')
      input.type = 'file'
      if (mimeTypes.length > 0) {
        input.accept = mimeTypes.join(',')
      }
      input.onchange = (e) => {
        const file = (e.target as HTMLInputElement).files?.[0]
        if (file && roundId) {
          uploadFileForRequirement(projectId, requirementId, file, roundId)
        }
      }
      input.click()
    },
    [roundId, uploadFileForRequirement]
  )

  // Handle bulk row upload
  const handleBulkUploadAll = useCallback(async () => {
    if (!bulkProject || !roundId) return

    const entries = Object.entries(bulkFiles).filter(
      ([, file]) => file !== null
    ) as Array<[string, File]>

    if (entries.length === 0) {
      toast.error('No files selected')
      return
    }

    // Upload all in parallel
    await Promise.allSettled(
      entries.map(([reqId, file]) =>
        uploadFileForRequirement(bulkProject.id, reqId, file, roundId)
      )
    )

    setBulkProject(null)
    setBulkFiles({})
    toast.success('Bulk upload complete')
  }, [bulkProject, bulkFiles, roundId, uploadFileForRequirement])

  const progressPercent =
    data && data.totalProjects > 0
      ? Math.round((data.completeCount / data.totalProjects) * 100)
      : 0

  return (
    <div className="space-y-6">
      {/* Header */}
      <div className="flex items-center gap-4">
        <Button variant="ghost" size="icon" onClick={() => router.back()}>
          <ArrowLeft className="h-4 w-4" />
        </Button>
        <div>
          <h1 className="text-2xl font-semibold tracking-tight">Bulk Document Upload</h1>
          <p className="text-muted-foreground">
            Upload required documents for multiple projects at once
          </p>
        </div>
      </div>

      {/* Round Selector */}
      <Card>
        <CardHeader>
          <CardTitle className="text-base">Round</CardTitle>
        </CardHeader>
        <CardContent>
          {roundsLoading ? (
            <Skeleton className="h-10 w-full" />
          ) : !rounds || rounds.length === 0 ? (
            <div className="flex items-center gap-2 text-sm text-muted-foreground">
              <AlertCircle className="h-4 w-4" />
              <span>No rounds have file requirements configured. Add file requirements to a round first.</span>
            </div>
          ) : (
            <Select
              value={roundId}
              onValueChange={(v) => {
                setRoundId(v)
                setPage(1)
                setUploads({})
              }}
            >
              <SelectTrigger>
                <SelectValue placeholder="Select a round..." />
              </SelectTrigger>
              <SelectContent>
                {rounds.map((r) => (
                  <SelectItem key={r.id} value={r.id}>
                    {r.competition.program.name} {r.competition.program.year} &mdash; {r.name}{' '}
                    ({r.fileRequirements.length} requirement
                    {r.fileRequirements.length !== 1 ? 's' : ''})
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          )}
        </CardContent>
      </Card>

      {/* Content (only if round selected) */}
      {roundId && data && (
        <>
          {/* Progress Summary */}
          <Card>
            <CardContent className="py-4">
              <div className="flex items-center justify-between mb-2">
                <p className="text-sm font-medium">
                  {data.completeCount} / {data.totalProjects} projects have complete documents
                </p>
                <Badge variant={progressPercent === 100 ? 'success' : 'secondary'}>
                  {progressPercent}%
                </Badge>
              </div>
              <Progress value={progressPercent} className="h-2" />
            </CardContent>
          </Card>

          {/* Filters */}
          <div className="flex flex-col gap-3 sm:flex-row sm:items-center">
            <div className="relative flex-1">
              <Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
              <Input
                value={search}
                onChange={(e) => handleSearchChange(e.target.value)}
                placeholder="Search by project name or team..."
                className="pl-10 pr-10"
              />
              {search && (
                <button
                  type="button"
                  onClick={() => {
                    setSearch('')
                    setDebouncedSearch('')
                    setPage(1)
                  }}
                  className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
                >
                  <X className="h-4 w-4" />
                </button>
              )}
            </div>
            <Select
              value={statusFilter}
              onValueChange={(v) => {
                setStatusFilter(v as 'all' | 'missing' | 'complete')
                setPage(1)
              }}
            >
              <SelectTrigger className="w-[180px]">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">All projects</SelectItem>
                <SelectItem value="missing">Missing files</SelectItem>
                <SelectItem value="complete">Complete</SelectItem>
              </SelectContent>
            </Select>
          </div>

          {/* Table */}
          {isLoading ? (
            <Card>
              <CardContent className="p-6">
                <div className="space-y-4">
                  {[...Array(5)].map((_, i) => (
                    <Skeleton key={i} className="h-12 w-full" />
                  ))}
                </div>
              </CardContent>
            </Card>
          ) : data.projects.length === 0 ? (
            <Card>
              <CardContent className="flex flex-col items-center justify-center py-12 text-center">
                <FileUp className="h-12 w-12 text-muted-foreground/50" />
                <p className="mt-2 font-medium">No projects found</p>
                <p className="text-sm text-muted-foreground">
                  {debouncedSearch ? 'Try adjusting your search' : 'No projects in this program'}
                </p>
              </CardContent>
            </Card>
          ) : (
            <>
              <Card>
                <div className="overflow-x-auto">
                  <Table>
                    <TableHeader>
                      <TableRow>
                        <TableHead className="min-w-[200px]">Project</TableHead>
                        <TableHead>Applicant</TableHead>
                        {data.requirements.map((req) => (
                          <TableHead key={req.id} className="min-w-[160px] text-center">
                            <div>
                              {req.label}
                              {req.required && (
                                <span className="text-destructive ml-0.5">*</span>
                              )}
                            </div>
                            <div className="text-[10px] font-normal text-muted-foreground">
                              {req.mimeTypes.join(', ') || 'Any'}
                            </div>
                          </TableHead>
                        ))}
                        <TableHead className="text-center">Actions</TableHead>
                      </TableRow>
                    </TableHeader>
                    <TableBody>
                      {data.projects.map((row) => {
                        const missingRequired = row.requirements.filter(
                          (r) => r.required && (!r.file || (r.file?.objectKey && missingFiles.has(r.file.objectKey)))
                        )
                        return (
                          <TableRow
                            key={row.project.id}
                            className={row.isComplete ? 'bg-green-50/50' : ''}
                          >
                            <TableCell>
                              <Link
                                href={`/admin/projects/${row.project.id}`}
                                className="font-medium hover:underline"
                              >
                                {row.project.title}
                              </Link>
                            </TableCell>
                            <TableCell className="text-sm text-muted-foreground">
                              {row.project.submittedBy?.name ||
                                row.project.submittedBy?.email ||
                                row.project.teamName ||
                                '-'}
                            </TableCell>
                            {row.requirements.map((req) => {
                              const uploadKey = `${row.project.id}:${req.requirementId}`
                              const uploadState = uploads[uploadKey]

                              return (
                                <TableCell key={req.requirementId} className="text-center">
                                  {uploadState?.status === 'uploading' ? (
                                    <div className="flex flex-col items-center gap-1">
                                      <Loader2 className="h-4 w-4 animate-spin text-primary" />
                                      <Progress
                                        value={uploadState.progress}
                                        className="h-1 w-16"
                                      />
                                      <span className="text-[10px] text-muted-foreground">
                                        {uploadState.progress}%
                                      </span>
                                    </div>
                                  ) : uploadState?.status === 'error' ? (
                                    <div className="flex flex-col items-center gap-1">
                                      <AlertCircle className="h-4 w-4 text-destructive" />
                                      <Button
                                        variant="ghost"
                                        size="sm"
                                        className="h-6 px-2 text-[10px]"
                                        onClick={() =>
                                          handleCellUpload(
                                            row.project.id,
                                            req.requirementId,
                                            req.mimeTypes
                                          )
                                        }
                                      >
                                        Retry
                                      </Button>
                                    </div>
                                  ) : req.file && req.file.objectKey && missingFiles.has(req.file.objectKey) ? (
                                    <div className="flex flex-col items-center gap-1">
                                      <AlertCircle className="h-4 w-4 text-amber-500" />
                                      <span className="text-[10px] text-amber-600 font-medium">Missing</span>
                                      <Button
                                        variant="outline"
                                        size="sm"
                                        className="h-6 px-2 text-[10px]"
                                        onClick={() =>
                                          handleCellUpload(
                                            row.project.id,
                                            req.requirementId,
                                            req.mimeTypes
                                          )
                                        }
                                      >
                                        Re-upload
                                      </Button>
                                    </div>
                                  ) : req.file || uploadState?.status === 'complete' ? (
                                    <div className="flex flex-col items-center gap-1">
                                      <div className="flex items-center gap-1">
                                        <CheckCircle2 className="h-4 w-4 text-green-600" />
                                        {req.file && (
                                          <button
                                            type="button"
                                            className="text-muted-foreground hover:text-destructive transition-colors cursor-pointer"
                                            title="Remove file"
                                            onClick={() => handleDeleteFile(req.file!.id)}
                                            disabled={deleteMutation.isPending}
                                          >
                                            <Trash2 className="h-3 w-3" />
                                          </button>
                                        )}
                                      </div>
                                      {req.file?.bucket && req.file?.objectKey ? (
                                        <button
                                          type="button"
                                          className="text-[10px] text-teal-600 hover:text-teal-800 hover:underline truncate max-w-[120px] flex items-center gap-0.5 cursor-pointer"
                                          onClick={() =>
                                            handleViewFile(req.file!.bucket, req.file!.objectKey)
                                          }
                                        >
                                          {req.file.fileName}
                                          <ExternalLink className="h-2.5 w-2.5 shrink-0" />
                                        </button>
                                      ) : (
                                        <span className="text-[10px] text-muted-foreground truncate max-w-[120px]">
                                          {req.file?.fileName ?? 'Uploaded'}
                                        </span>
                                      )}
                                    </div>
                                  ) : (
                                    <Button
                                      variant="outline"
                                      size="sm"
                                      className="h-7 text-xs"
                                      onClick={() =>
                                        handleCellUpload(
                                          row.project.id,
                                          req.requirementId,
                                          req.mimeTypes
                                        )
                                      }
                                    >
                                      <Upload className="mr-1 h-3 w-3" />
                                      Upload
                                    </Button>
                                  )}
                                </TableCell>
                              )
                            })}
                            <TableCell className="text-center">
                              {missingRequired.length > 0 && (
                                <Button
                                  variant="secondary"
                                  size="sm"
                                  className="h-7 text-xs"
                                  onClick={() => {
                                    setBulkProject({
                                      id: row.project.id,
                                      title: row.project.title,
                                      requirements: row.requirements,
                                    })
                                    setBulkFiles({})
                                  }}
                                >
                                  <FileUp className="mr-1 h-3 w-3" />
                                  Upload All ({missingRequired.length})
                                </Button>
                              )}
                              {row.isComplete && (
                                <Badge variant="success" className="text-xs">
                                  Complete
                                </Badge>
                              )}
                            </TableCell>
                          </TableRow>
                        )
                      })}
                    </TableBody>
                  </Table>
                </div>
              </Card>

              <Pagination
                page={data.page}
                totalPages={data.totalPages}
                total={data.total}
                perPage={perPage}
                onPageChange={setPage}
                onPerPageChange={(pp) => {
                  setPerPage(pp)
                  setPage(1)
                }}
              />
            </>
          )}
        </>
      )}

      {/* Bulk Upload Dialog */}
      <Dialog
        open={!!bulkProject}
        onOpenChange={(open) => {
          if (!open) {
            setBulkProject(null)
            setBulkFiles({})
          }
        }}
      >
        <DialogContent className="sm:max-w-lg">
          <DialogHeader>
            <DialogTitle>Upload Files for {bulkProject?.title}</DialogTitle>
            <DialogDescription>
              Select files for each missing requirement, then upload all at once.
            </DialogDescription>
          </DialogHeader>

          {bulkProject && (
            <div className="space-y-4 py-2">
              {bulkProject.requirements
                .filter((r) => !r.file)
                .map((req) => {
                  const selectedFile = bulkFiles[req.requirementId]
                  const uploadKey = `${bulkProject.id}:${req.requirementId}`
                  const uploadState = uploads[uploadKey]

                  return (
                    <div
                      key={req.requirementId}
                      className={cn(
                        'flex items-center gap-3 rounded-lg border p-3',
                        uploadState?.status === 'complete' &&
                          'border-green-500/50 bg-green-500/5',
                        uploadState?.status === 'error' &&
                          'border-destructive/50 bg-destructive/5'
                      )}
                    >
                      <div className="flex-1 min-w-0">
                        <p className="text-sm font-medium">
                          {req.label}
                          {req.required && (
                            <span className="text-destructive ml-0.5">*</span>
                          )}
                        </p>
                        <p className="text-xs text-muted-foreground">
                          {req.mimeTypes.join(', ') || 'Any file type'}
                        </p>

                        {selectedFile && !uploadState && (
                          <div className="flex items-center gap-2 mt-1">
                            <Badge variant="outline" className="text-xs">
                              {selectedFile.name}
                            </Badge>
                            <span className="text-[10px] text-muted-foreground">
                              {formatFileSize(selectedFile.size)}
                            </span>
                            <button
                              type="button"
                              onClick={() =>
                                setBulkFiles((prev) => ({
                                  ...prev,
                                  [req.requirementId]: null,
                                }))
                              }
                              className="text-muted-foreground hover:text-foreground"
                            >
                              <X className="h-3 w-3" />
                            </button>
                          </div>
                        )}

                        {uploadState?.status === 'uploading' && (
                          <div className="flex items-center gap-2 mt-1">
                            <Progress
                              value={uploadState.progress}
                              className="h-1 flex-1"
                            />
                            <span className="text-xs text-muted-foreground">
                              {uploadState.progress}%
                            </span>
                          </div>
                        )}

                        {uploadState?.status === 'error' && (
                          <p className="text-xs text-destructive mt-1">
                            {uploadState.error}
                          </p>
                        )}
                      </div>

                      <div className="shrink-0">
                        {uploadState?.status === 'complete' ? (
                          <CheckCircle2 className="h-5 w-5 text-green-600" />
                        ) : uploadState?.status === 'uploading' ? (
                          <Loader2 className="h-5 w-5 animate-spin text-primary" />
                        ) : (
                          <>
                            <input
                              ref={(el) => {
                                fileInputRefs.current[req.requirementId] = el
                              }}
                              type="file"
                              className="hidden"
                              accept={
                                req.mimeTypes.length > 0
                                  ? req.mimeTypes.join(',')
                                  : undefined
                              }
                              onChange={(e) => {
                                const file = e.target.files?.[0]
                                if (file) {
                                  setBulkFiles((prev) => ({
                                    ...prev,
                                    [req.requirementId]: file,
                                  }))
                                }
                                e.target.value = ''
                              }}
                            />
                            <Button
                              variant="outline"
                              size="sm"
                              className="h-8"
                              onClick={() =>
                                fileInputRefs.current[req.requirementId]?.click()
                              }
                            >
                              {selectedFile ? 'Change' : 'Select'}
                            </Button>
                          </>
                        )}
                      </div>
                    </div>
                  )
                })}

              <div className="flex justify-end gap-2 pt-2 border-t">
                <Button
                  variant="outline"
                  onClick={() => {
                    setBulkProject(null)
                    setBulkFiles({})
                  }}
                >
                  Cancel
                </Button>
                <Button
                  onClick={handleBulkUploadAll}
                  disabled={
                    Object.values(bulkFiles).filter(Boolean).length === 0 ||
                    Object.values(uploads).some((u) => u.status === 'uploading')
                  }
                >
                  {Object.values(uploads).some((u) => u.status === 'uploading') ? (
                    <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                  ) : (
                    <Upload className="mr-2 h-4 w-4" />
                  )}
                  Upload {Object.values(bulkFiles).filter(Boolean).length} File
                  {Object.values(bulkFiles).filter(Boolean).length !== 1 ? 's' : ''}
                </Button>
              </div>
            </div>
          )}
        </DialogContent>
      </Dialog>
    </div>
  )
}
