'use client'

import { useState, useRef, useCallback, useEffect } from 'react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { ScrollArea } from '@/components/ui/scroll-area'
import {
  Folder,
  File,
  Upload,
  Download,
  ChevronRight,
  ArrowLeft,
  X,
  CheckCircle2,
  AlertCircle,
  Loader2,
} from 'lucide-react'

interface FileEntry {
  name: string
  is_dir: boolean
  size: number
  path: string
}

interface TransferItem {
  id: string
  name: string
  direction: 'upload' | 'download'
  status: 'pending' | 'transferring' | 'done' | 'error'
  progress: number
  error?: string
}

interface FileTransferPanelProps {
  onClose: () => void
  sendEvent: (event: Record<string, unknown>) => void
  incomingMessage: Record<string, unknown> | null
}

export function FileTransferPanel({ onClose, sendEvent, incomingMessage }: FileTransferPanelProps) {
  const [remotePath, setRemotePath] = useState('~')
  const [remoteEntries, setRemoteEntries] = useState<FileEntry[]>([])
  const [remoteParent, setRemoteParent] = useState<string | null>(null)
  const [transfers, setTransfers] = useState<TransferItem[]>([])
  const [isDragOver, setIsDragOver] = useState(false)
  const [isLoadingDir, setIsLoadingDir] = useState(false)
  const fileInputRef = useRef<HTMLInputElement>(null)
  // Download accumulation: transfer_id → {chunks: string[], filename: string, size: number}
  const downloadBuffers = useRef<Record<string, {chunks: string[], filename: string, size: number}>>({})

  const browseRemote = useCallback((path: string) => {
    setIsLoadingDir(true)
    sendEvent({ type: 'list_files', path })
  }, [sendEvent])

  useEffect(() => {
    browseRemote('~')
  }, [browseRemote])

  // Handle incoming relay messages
  useEffect(() => {
    if (!incomingMessage) return
    const msg = incomingMessage

    if (msg.type === 'file_list') {
      setIsLoadingDir(false)
      setRemotePath(msg.path as string)
      setRemoteParent((msg.parent as string) ?? null)
      setRemoteEntries((msg.entries as FileEntry[]) ?? [])
    }

    if (msg.type === 'file_chunk') {
      const tid = msg.transfer_id as string || ''
      const done = msg.done as boolean

      if (msg.upload_complete) {
        setTransfers(prev => prev.map(t =>
          t.id === tid ? { ...t, status: 'done', progress: 100 } : t
        ))
        return
      }

      if (msg.error) {
        setTransfers(prev => prev.map(t =>
          t.id === tid ? { ...t, status: 'error', error: msg.error as string } : t
        ))
        return
      }

      // Download chunks
      const filename = msg.filename as string || 'download'
      const totalSize = msg.size as number || 0
      const chunk = msg.chunk as string || ''

      if (!downloadBuffers.current[tid]) {
        downloadBuffers.current[tid] = { chunks: [], filename, size: totalSize }
      }
      if (chunk) {
        downloadBuffers.current[tid].chunks.push(chunk)
        const received = downloadBuffers.current[tid].chunks.reduce((sum, c) => sum + c.length * 0.75, 0)
        const progress = totalSize > 0 ? Math.min(99, Math.round((received / totalSize) * 100)) : 50
        setTransfers(prev => prev.map(t =>
          t.id === tid ? { ...t, status: 'transferring', progress } : t
        ))
      }

      if (done) {
        const buf = downloadBuffers.current[tid]
        if (buf) {
          delete downloadBuffers.current[tid]
          // Decode base64 chunks and create blob
          const binaryChunks = buf.chunks.map(c => {
            const binary = atob(c)
            const bytes = new Uint8Array(binary.length)
            for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)
            return bytes
          })
          const blob = new Blob(binaryChunks)
          const url = URL.createObjectURL(blob)
          const a = document.createElement('a')
          a.href = url
          a.download = buf.filename
          a.click()
          URL.revokeObjectURL(url)
          setTransfers(prev => prev.map(t =>
            t.id === tid ? { ...t, status: 'done', progress: 100 } : t
          ))
        }
      }
    }
  }, [incomingMessage])

  const uploadFiles = useCallback(async (files: FileList | File[]) => {
    const fileArr = Array.from(files)
    for (const file of fileArr) {
      const tid = crypto.randomUUID()
      setTransfers(prev => [{ id: tid, name: file.name, direction: 'upload', status: 'pending', progress: 0 }, ...prev])

      const destPath = remotePath === '~' ? '~/Downloads' : remotePath
      sendEvent({ type: 'file_upload_start', transfer_id: tid, filename: file.name, dest_path: destPath })

      const CHUNK = 65536
      const reader = file.stream().getReader()
      let seq = 0
      let sent = 0
      const total = file.size

      const pump = async () => {
        while (true) {
          const { done, value } = await reader.read()
          if (done) break
          // Convert to base64
          const b64 = btoa(String.fromCharCode(...value))
          sendEvent({ type: 'file_upload_chunk', transfer_id: tid, seq: seq++, chunk: b64 })
          sent += value.length
          const progress = Math.min(99, Math.round((sent / total) * 100))
          setTransfers(prev => prev.map(t => t.id === tid ? { ...t, status: 'transferring', progress } : t))
        }
      }
      await pump()
      sendEvent({ type: 'file_upload_end', transfer_id: tid })
    }
  }, [sendEvent, remotePath])

  const downloadFile = useCallback((entry: FileEntry) => {
    const tid = crypto.randomUUID()
    setTransfers(prev => [{ id: tid, name: entry.name, direction: 'download', status: 'pending', progress: 0 }, ...prev])
    downloadBuffers.current[tid] = { chunks: [], filename: entry.name, size: entry.size }
    sendEvent({ type: 'file_download', path: entry.path, transfer_id: tid })
  }, [sendEvent])

  const handleDrop = useCallback((e: React.DragEvent) => {
    e.preventDefault()
    setIsDragOver(false)
    if (e.dataTransfer.files.length > 0) uploadFiles(e.dataTransfer.files)
  }, [uploadFiles])

  const formatSize = (bytes: number) => {
    if (bytes < 1024) return `${bytes} B`
    if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} KB`
    return `${(bytes / 1048576).toFixed(1)} MB`
  }

  return (
    <div className="w-80 border-l border-border/50 bg-card flex flex-col h-full">
      {/* Header */}
      <div className="flex items-center justify-between p-3 border-b border-border/50">
        <span className="text-sm font-medium">File Transfer</span>
        <Button variant="ghost" size="icon" className="h-6 w-6" onClick={onClose}>
          <X className="h-3.5 w-3.5" />
        </Button>
      </div>

      {/* Remote file browser */}
      <div className="flex flex-col flex-1 min-h-0">
        <div className="p-2 border-b border-border/50">
          <div className="flex items-center gap-1 mb-1.5">
            {remoteParent && (
              <Button variant="ghost" size="icon" className="h-6 w-6 shrink-0" onClick={() => browseRemote(remoteParent)}>
                <ArrowLeft className="h-3.5 w-3.5" />
              </Button>
            )}
            <span className="text-xs text-muted-foreground truncate flex-1 font-mono">{remotePath}</span>
            {isLoadingDir && <Loader2 className="h-3.5 w-3.5 animate-spin text-muted-foreground shrink-0" />}
          </div>
        </div>

        <ScrollArea className="flex-1">
          <div className="p-1">
            {remoteEntries.map((entry) => (
              <div
                key={entry.path}
                className="flex items-center gap-2 px-2 py-1 rounded hover:bg-muted/50 cursor-pointer group"
                onClick={() => entry.is_dir ? browseRemote(entry.path) : undefined}
              >
                {entry.is_dir
                  ? <Folder className="h-4 w-4 text-blue-400 shrink-0" />
                  : <File className="h-4 w-4 text-muted-foreground shrink-0" />
                }
                <span className="text-xs truncate flex-1">{entry.name}</span>
                {!entry.is_dir && (
                  <>
                    <span className="text-xs text-muted-foreground shrink-0">{formatSize(entry.size)}</span>
                    <Button
                      variant="ghost"
                      size="icon"
                      className="h-5 w-5 opacity-0 group-hover:opacity-100 shrink-0"
                      onClick={(e) => { e.stopPropagation(); downloadFile(entry) }}
                      title="Download"
                    >
                      <Download className="h-3 w-3" />
                    </Button>
                  </>
                )}
                {entry.is_dir && <ChevronRight className="h-3.5 w-3.5 text-muted-foreground shrink-0" />}
              </div>
            ))}
            {remoteEntries.length === 0 && !isLoadingDir && (
              <p className="text-xs text-muted-foreground text-center py-4">Empty directory</p>
            )}
          </div>
        </ScrollArea>

        {/* Upload drop zone */}
        <div
          className={`m-2 border-2 border-dashed rounded-lg p-3 text-center transition-colors cursor-pointer ${
            isDragOver ? 'border-primary bg-primary/5' : 'border-border/50 hover:border-border'
          }`}
          onDragOver={(e) => { e.preventDefault(); setIsDragOver(true) }}
          onDragLeave={() => setIsDragOver(false)}
          onDrop={handleDrop}
          onClick={() => fileInputRef.current?.click()}
        >
          <Upload className="h-4 w-4 mx-auto mb-1 text-muted-foreground" />
          <p className="text-xs text-muted-foreground">Drop files to upload</p>
          <p className="text-xs text-muted-foreground">or click to browse</p>
          <input
            ref={fileInputRef}
            type="file"
            multiple
            className="hidden"
            onChange={(e) => e.target.files && uploadFiles(e.target.files)}
          />
        </div>
      </div>

      {/* Transfer queue */}
      {transfers.length > 0 && (
        <div className="border-t border-border/50">
          <div className="p-2">
            <p className="text-xs font-medium text-muted-foreground mb-1">Transfers</p>
            <div className="space-y-1 max-h-36 overflow-y-auto">
              {transfers.map((t) => (
                <div key={t.id} className="flex items-center gap-2 text-xs">
                  {t.direction === 'upload'
                    ? <Upload className="h-3 w-3 text-muted-foreground shrink-0" />
                    : <Download className="h-3 w-3 text-muted-foreground shrink-0" />
                  }
                  <span className="truncate flex-1">{t.name}</span>
                  {t.status === 'done' && <CheckCircle2 className="h-3 w-3 text-green-500 shrink-0" />}
                  {t.status === 'error' && <AlertCircle className="h-3 w-3 text-destructive shrink-0" />}
                  {t.status === 'transferring' && (
                    <span className="shrink-0 text-muted-foreground">{t.progress}%</span>
                  )}
                  {t.status === 'pending' && <Loader2 className="h-3 w-3 animate-spin shrink-0" />}
                </div>
              ))}
            </div>
          </div>
        </div>
      )}
    </div>
  )
}
