'use client'

import { useCallback, useEffect, useRef, useState } from 'react'
import { createLogger } from '@sim/logger'
import { RotateCcw, X } from 'lucide-react'
import { useParams } from 'next/navigation'
import {
  Button,
  Label,
  Loader,
  Modal,
  ModalBody,
  ModalContent,
  ModalDescription,
  ModalFooter,
  ModalHeader,
} from '@/components/emcn'
import { cn } from '@/lib/core/utils/cn'
import { formatFileSize, validateKnowledgeBaseFile } from '@/lib/uploads/utils/file-utils'
import { ACCEPT_ATTRIBUTE } from '@/lib/uploads/utils/validation'
import { useKnowledgeUpload } from '@/app/workspace/[workspaceId]/knowledge/hooks/use-knowledge-upload'

const logger = createLogger('AddDocumentsModal')

interface FileWithPreview extends File {
  preview: string
}

interface AddDocumentsModalProps {
  open: boolean
  onOpenChange: (open: boolean) => void
  knowledgeBaseId: string
  chunkingConfig?: {
    maxSize: number
    minSize: number
    overlap: number
  }
}

export function AddDocumentsModal({
  open,
  onOpenChange,
  knowledgeBaseId,
  chunkingConfig,
}: AddDocumentsModalProps) {
  const params = useParams()
  const workspaceId = params.workspaceId as string
  const fileInputRef = useRef<HTMLInputElement>(null)
  const [files, setFiles] = useState<FileWithPreview[]>([])
  const [fileError, setFileError] = useState<string | null>(null)
  const [isDragging, setIsDragging] = useState(false)
  const dragCounterRef = useRef(0)
  const [retryingIndexes, setRetryingIndexes] = useState<Set<number>>(() => new Set())

  const { isUploading, uploadProgress, uploadFiles, uploadError, clearError } = useKnowledgeUpload({
    workspaceId,
  })

  useEffect(() => {
    return () => {
      files.forEach((file) => {
        if (file.preview) {
          URL.revokeObjectURL(file.preview)
        }
      })
    }
  }, [files])

  useEffect(() => {
    if (open) {
      setFiles([])
      setFileError(null)
      setIsDragging(false)
      dragCounterRef.current = 0
      setRetryingIndexes(new Set())
      clearError()
    }
  }, [open, clearError])

  /** Handles close with upload guard */
  const handleOpenChange = useCallback(
    (newOpen: boolean) => {
      if (!newOpen) {
        if (isUploading) return
        setFiles([])
        setFileError(null)
        clearError()
        setIsDragging(false)
        dragCounterRef.current = 0
        setRetryingIndexes(new Set())
      }
      onOpenChange(newOpen)
    },
    [isUploading, clearError, onOpenChange]
  )

  const handleClose = () => {
    handleOpenChange(false)
  }

  const processFiles = async (fileList: FileList | File[]) => {
    setFileError(null)

    if (!fileList || fileList.length === 0) return

    try {
      const newFiles: FileWithPreview[] = []
      let hasError = false

      for (const file of Array.from(fileList)) {
        const validationError = validateKnowledgeBaseFile(file)
        if (validationError) {
          setFileError(validationError)
          hasError = true
          continue
        }

        const fileWithPreview = Object.assign(file, {
          preview: URL.createObjectURL(file),
        }) as FileWithPreview

        newFiles.push(fileWithPreview)
      }

      if (!hasError && newFiles.length > 0) {
        setFiles((prev) => [...prev, ...newFiles])
      }
    } catch (error) {
      logger.error('Error processing files:', error)
      setFileError('An error occurred while processing files. Please try again.')
    } finally {
      if (fileInputRef.current) {
        fileInputRef.current.value = ''
      }
    }
  }

  const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
    if (e.target.files) {
      await processFiles(e.target.files)
    }
  }

  const handleDragEnter = (e: React.DragEvent) => {
    e.preventDefault()
    e.stopPropagation()
    dragCounterRef.current += 1
    if (dragCounterRef.current === 1) {
      setIsDragging(true)
    }
  }

  const handleDragLeave = (e: React.DragEvent) => {
    e.preventDefault()
    e.stopPropagation()
    dragCounterRef.current -= 1
    if (dragCounterRef.current === 0) {
      setIsDragging(false)
    }
  }

  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault()
    e.stopPropagation()
    e.dataTransfer.dropEffect = 'copy'
  }

  const handleDrop = async (e: React.DragEvent) => {
    e.preventDefault()
    e.stopPropagation()
    setIsDragging(false)
    dragCounterRef.current = 0

    if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
      await processFiles(e.dataTransfer.files)
    }
  }

  const removeFile = (index: number) => {
    setFiles((prev) => {
      URL.revokeObjectURL(prev[index].preview)
      return prev.filter((_, i) => i !== index)
    })
  }

  const handleRetryFile = async (index: number) => {
    const fileToRetry = files[index]
    if (!fileToRetry) return

    setRetryingIndexes((prev) => new Set(prev).add(index))

    try {
      await uploadFiles([fileToRetry], knowledgeBaseId, {
        recipe: 'default',
      })
      removeFile(index)
    } catch (error) {
      logger.error('Error retrying file upload:', error)
    } finally {
      setRetryingIndexes((prev) => {
        const newSet = new Set(prev)
        newSet.delete(index)
        return newSet
      })
    }
  }

  const handleUpload = async () => {
    if (files.length === 0) return

    try {
      await uploadFiles(files, knowledgeBaseId, {
        recipe: 'default',
      })
      logger.info(`Successfully uploaded ${files.length} files`)
      handleClose()
    } catch (error) {
      logger.error('Error uploading files:', error)
    }
  }

  return (
    <Modal open={open} onOpenChange={handleOpenChange}>
      <ModalContent size='md'>
        <ModalHeader>New Documents</ModalHeader>
        <ModalDescription className='sr-only'>
          Upload files to add as documents to this knowledge base
        </ModalDescription>

        <ModalBody>
          <div className='min-h-0 flex-1 overflow-y-auto'>
            <div className='space-y-3'>
              {fileError && (
                <p className='text-[var(--text-error)] text-caption leading-tight'>{fileError}</p>
              )}

              <div className='flex flex-col gap-2'>
                <Label>Upload Documents</Label>
                <Button
                  type='button'
                  variant='default'
                  onClick={() => fileInputRef.current?.click()}
                  onDragEnter={handleDragEnter}
                  onDragOver={handleDragOver}
                  onDragLeave={handleDragLeave}
                  onDrop={handleDrop}
                  className={cn(
                    '!bg-[var(--surface-1)] hover-hover:!bg-[var(--surface-4)] w-full justify-center border border-[var(--border-1)] border-dashed py-2.5',
                    isDragging && 'border-[var(--surface-7)]'
                  )}
                >
                  <input
                    ref={fileInputRef}
                    type='file'
                    accept={ACCEPT_ATTRIBUTE}
                    onChange={handleFileChange}
                    className='hidden'
                    multiple
                  />
                  <div className='flex flex-col gap-0.5 text-center'>
                    <span className='text-[var(--text-primary)]'>
                      {isDragging ? 'Drop files here' : 'Drop files here or click to browse'}
                    </span>
                    <span className='text-[var(--text-tertiary)] text-xs'>
                      PDF, DOC, DOCX, TXT, CSV, XLS, XLSX, MD, PPT, PPTX, HTML, JSONL (max 100MB
                      each)
                    </span>
                  </div>
                </Button>
              </div>

              {files.length > 0 && (
                <div className='space-y-2'>
                  <Label>Selected Files</Label>
                  <div className='space-y-2'>
                    {files.map((file, index) => {
                      const fileStatus = uploadProgress.fileStatuses?.[index]
                      const isFailed = fileStatus?.status === 'failed'
                      const isRetrying = retryingIndexes.has(index)
                      const isProcessing = fileStatus?.status === 'uploading' || isRetrying

                      return (
                        <div
                          key={`${file.name}-${file.size}`}
                          className={cn(
                            'flex items-center gap-2 rounded-sm border p-2',
                            isFailed && !isRetrying && 'border-[var(--text-error)]'
                          )}
                        >
                          <span
                            className={cn(
                              'min-w-0 flex-1 truncate text-caption',
                              isFailed && !isRetrying && 'text-[var(--text-error)]'
                            )}
                            title={file.name}
                          >
                            {file.name}
                          </span>
                          <span className='flex-shrink-0 text-[var(--text-muted)] text-xs'>
                            {formatFileSize(file.size)}
                          </span>
                          <div className='flex flex-shrink-0 items-center gap-1'>
                            {isProcessing ? (
                              <Loader className='size-4 text-[var(--text-muted)]' animate />
                            ) : (
                              <>
                                {isFailed && (
                                  <Button
                                    type='button'
                                    variant='ghost'
                                    className='size-4 p-0'
                                    onClick={() => handleRetryFile(index)}
                                    disabled={isUploading}
                                  >
                                    <RotateCcw className='size-3' />
                                  </Button>
                                )}
                                <Button
                                  type='button'
                                  variant='ghost'
                                  className='size-4 p-0'
                                  onClick={() => removeFile(index)}
                                  disabled={isUploading}
                                >
                                  <X className='size-3.5' />
                                </Button>
                              </>
                            )}
                          </div>
                        </div>
                      )
                    })}
                  </div>
                </div>
              )}
            </div>
          </div>
        </ModalBody>

        <ModalFooter>
          <div className='flex w-full items-center justify-between gap-3'>
            {uploadError ? (
              <p className='min-w-0 flex-1 truncate text-[var(--text-error)] text-caption leading-tight'>
                {uploadError.message}
              </p>
            ) : (
              <div />
            )}
            <div className='flex flex-shrink-0 gap-2'>
              <Button variant='default' onClick={handleClose} type='button' disabled={isUploading}>
                Cancel
              </Button>
              <Button
                variant='primary'
                type='button'
                onClick={handleUpload}
                disabled={files.length === 0 || isUploading}
              >
                {isUploading
                  ? uploadProgress.stage === 'uploading'
                    ? `Uploading ${uploadProgress.filesCompleted}/${uploadProgress.totalFiles}...`
                    : uploadProgress.stage === 'processing'
                      ? 'Processing...'
                      : 'Uploading...'
                  : 'Upload'}
              </Button>
            </div>
          </div>
        </ModalFooter>
      </ModalContent>
    </Modal>
  )
}
