import { useRef, useState } from 'react'
import type { FolderEntry } from '@/lib/client-types'
import { validateFolder } from '@/lib/validate-folder'
import { FolderIcon } from '@/components/ui/icons'

function readDroppedFile(entry: FileSystemFileEntry) {
  return new Promise<File>((resolve, reject) => {
    entry.file(resolve, reject)
  })
}

function readDirectoryEntries(reader: FileSystemDirectoryReader) {
  return new Promise<FileSystemEntry[]>((resolve, reject) => {
    reader.readEntries(resolve, reject)
  })
}

async function collectEntryFiles(entry: FileSystemEntry): Promise<File[]> {
  if (entry.isFile) {
    return [await readDroppedFile(entry as FileSystemFileEntry)]
  }

  const reader = (entry as FileSystemDirectoryEntry).createReader()
  const files: File[] = []

  while (true) {
    const entries = await readDirectoryEntries(reader)
    if (entries.length === 0) break

    for (const child of entries) {
      files.push(...await collectEntryFiles(child))
    }
  }

  return files
}

interface FolderDropzoneProps {
  isUploading: boolean
  onFolderSelected: (entry: FolderEntry) => void
  onError: (message: string) => void
}

export default function FolderDropzone({
  isUploading,
  onFolderSelected,
  onError,
}: FolderDropzoneProps) {
  const inputRef = useRef<HTMLInputElement>(null)
  const [isDragActive, setIsDragActive] = useState(false)

  const processFiles = (files: File[], fallbackFolderName = 'folder') => {
    if (files.length === 0) return

    const folderName = files[0].webkitRelativePath?.split('/')[0] || fallbackFolderName
    const validation = validateFolder(files)

    if (!validation.ok) {
      onError(validation.errors.join(' | '))
      return
    }

    const entry: FolderEntry = {
      folderName,
      modelFile: validation.model,
      textures: validation.textures,
      status: 'pending',
      progress: 0,
      warnings: validation.warnings,
      modelUrl: URL.createObjectURL(validation.model),
      viewerOpen: true,
    }

    onFolderSelected(entry)
  }

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const selected = e.target.files
    if (!selected || selected.length === 0) return

    processFiles(Array.from(selected))
    e.target.value = ''
  }

  const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault()

    if (isUploading) return
    setIsDragActive(true)
  }

  const handleDragLeave = (e: React.DragEvent<HTMLDivElement>) => {
    if (!e.currentTarget.contains(e.relatedTarget as Node | null)) {
      setIsDragActive(false)
    }
  }

  const handleDrop = async (e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault()
    setIsDragActive(false)

    if (isUploading) return

    try {
      const items = Array.from(e.dataTransfer.items)
      const rootEntries = items
        .filter((item) => item.kind === 'file')
        .map((item) => item.webkitGetAsEntry?.())
        .filter((entry): entry is FileSystemEntry => entry !== null)

      const directoryEntries = rootEntries.filter((entry) => entry.isDirectory)

      if (directoryEntries.length > 0) {
        if (directoryEntries.length > 1) {
          onError('Deposez un seul dossier a la fois')
          return
        }

        const rootEntry = directoryEntries[0] as FileSystemDirectoryEntry
        const files = await collectEntryFiles(rootEntry)
        processFiles(files, rootEntry.name)
        return
      }

      const droppedFiles = Array.from(e.dataTransfer.files)
      if (droppedFiles.length === 0) return

      processFiles(droppedFiles)
    } catch {
      onError('Impossible de lire le dossier depose')
    }
  }

  return (
    <>
      <input
        type="file"
        id="folder-input"
        ref={inputRef}
        {...({ webkitdirectory: '', directory: '' } as React.InputHTMLAttributes<HTMLInputElement>)}
        multiple
        className="hidden"
        disabled={isUploading}
        onChange={handleChange}
      />

      <div
        onClick={() => {
          if (isUploading) return
          inputRef.current?.click()
        }}
        onDragOver={handleDragOver}
        onDragLeave={handleDragLeave}
        onDrop={(e) => {
          void handleDrop(e)
        }}
        className={`
          relative border-2 border-dashed rounded-2xl p-8 text-center cursor-pointer transition-all duration-200 bg-black-800
          ${isUploading ? 'cursor-not-allowed opacity-60 border-white/20' : ''}
          ${!isUploading ? 'border-white/30 hover:border-white/50 hover:bg-black-700' : ''}
          ${isDragActive ? 'border-white/70 bg-black-700' : ''}
        `}
      >
        <div className="flex justify-center mb-3">
          <div className="w-12 h-12 rounded-full flex items-center justify-center bg-black-700">
            <FolderIcon className="w-6 h-6 text-gray-400" />
          </div>
        </div>
        <p className="text-sm font-medium text-gray-300">
          Deposez votre dossier ici
          <span className="text-gray-500 font-normal"> ou cliquez pour parcourir</span>
        </p>
        <p className="text-xs text-gray-500 mt-1">
          Contenu attendu : model.glb/gltf + textures (roughness, normal, metalness, color, displace)
          <br />Les originaux sont archives sur le Drive, les comprimes sont envoyes sur Git.
        </p>
      </div>
    </>
  )
}
