"use client";

import { useCallback, useRef, useState, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { 
  Folder, 
  FolderOpen, 
  Image as ImageIcon, 
  Trash2, 
  Upload, 
  X,
  ChevronDown,
  ChevronRight 
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { useAtlasStore, type BrowserSprite } from "@/store/atlasStore";
import { useSafeTranslation } from "@/lib/i18n";

/**
 * Generate unique ID
 */
function generateId(): string {
  return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
}

/**
 * Natural sort comparator for filenames
 */
function naturalSort(a: string, b: string): number {
  return a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" });
}

/**
 * Check if file is an image
 */
function isImageFile(file: File): boolean {
  const imageTypes = ["image/png", "image/jpeg", "image/jpg", "image/webp", "image/gif", "image/bmp"];
  return imageTypes.includes(file.type) || /\.(png|jpe?g|webp|gif|bmp)$/i.test(file.name);
}

/**
 * Load image file as BrowserSprite
 */
async function loadImageAsSprite(file: File): Promise<BrowserSprite> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    
    reader.onload = async () => {
      try {
        const blob = new Blob([reader.result as ArrayBuffer], { type: file.type });
        const imageBitmap = await createImageBitmap(blob);
        
        resolve({
          id: generateId(),
          name: file.name,
          width: imageBitmap.width,
          height: imageBitmap.height,
          image: imageBitmap,
          file,
        });
      } catch (error) {
        reject(error);
      }
    };
    
    reader.onerror = () => reject(new Error("Failed to read file"));
    reader.readAsArrayBuffer(file);
  });
}

export function FileListPanel() {
  const { t } = useSafeTranslation();
  const fileInputRef = useRef<HTMLInputElement>(null);
  const folderInputRef = useRef<HTMLInputElement>(null);
  const dropZoneRef = useRef<HTMLDivElement>(null);
  
  const [isDragging, setIsDragging] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [isExpanded, setIsExpanded] = useState(true);
  
  const { 
    sprites, 
    folderName, 
    addSprites, 
    removeSprite, 
    clearSprites, 
    setFolderName,
    selectedSpriteIds,
    selectSprite,
    setStatus,
  } = useAtlasStore();

  /**
   * Process uploaded files
   */
  const processFiles = useCallback(async (files: FileList | File[]) => {
    const fileArray = Array.from(files);
    const imageFiles = fileArray.filter(isImageFile);
    
    if (imageFiles.length === 0) return;

    setIsLoading(true);
    setStatus("loading");

    try {
      // Sort by filename
      imageFiles.sort((a, b) => naturalSort(a.name, b.name));

      // Extract folder name from first file's path
      const firstFile = imageFiles[0];
      if (firstFile.webkitRelativePath) {
        const pathParts = firstFile.webkitRelativePath.split("/");
        if (pathParts.length > 1) {
          setFolderName(pathParts[0]);
        }
      }

      // Load all images
      const loadPromises = imageFiles.map((file) => loadImageAsSprite(file));
      const loadedSprites = await Promise.all(loadPromises);
      
      addSprites(loadedSprites);
      setStatus("idle");
    } catch (error) {
      console.error("Failed to load images:", error);
      setStatus("error");
    } finally {
      setIsLoading(false);
    }
  }, [addSprites, setFolderName, setStatus]);

  /**
   * Handle drag events
   */
  const handleDragEnter = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragging(true);
  }, []);

  const handleDragLeave = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    
    // Check if we're leaving the drop zone
    if (dropZoneRef.current && !dropZoneRef.current.contains(e.relatedTarget as Node)) {
      setIsDragging(false);
    }
  }, []);

  const handleDragOver = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
  }, []);

  const handleDrop = useCallback(async (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragging(false);

    const items = e.dataTransfer.items;
    const dataTransferFiles = e.dataTransfer.files;
    const files: File[] = [];

    // Read all entries from a directory (handles batched readEntries)
    const readAllEntries = async (reader: FileSystemDirectoryReader): Promise<FileSystemEntry[]> => {
      const allEntries: FileSystemEntry[] = [];
      
      const readBatch = (): Promise<FileSystemEntry[]> => {
        return new Promise((resolve) => {
          reader.readEntries((entries) => resolve(entries));
        });
      };

      // readEntries may return results in batches, keep reading until empty
      let batch = await readBatch();
      while (batch.length > 0) {
        allEntries.push(...batch);
        batch = await readBatch();
      }
      
      return allEntries;
    };

    // Handle folder drop
    const processEntry = async (entry: FileSystemEntry): Promise<void> => {
      if (entry.isFile) {
        const fileEntry = entry as FileSystemFileEntry;
        return new Promise((resolve) => {
          fileEntry.file((file) => {
            if (isImageFile(file)) {
              // Add webkitRelativePath-like info
              Object.defineProperty(file, "webkitRelativePath", {
                value: entry.fullPath.substring(1), // Remove leading slash
                writable: false,
              });
              files.push(file);
            }
            resolve();
          });
        });
      } else if (entry.isDirectory) {
        const dirEntry = entry as FileSystemDirectoryEntry;
        const reader = dirEntry.createReader();
        const entries = await readAllEntries(reader);
        
        for (const childEntry of entries) {
          await processEntry(childEntry);
        }
      }
    };

    // Check if webkitGetAsEntry is supported
    let hasEntrySupport = false;
    if (items && items.length > 0 && typeof items[0].webkitGetAsEntry === "function") {
      hasEntrySupport = true;
    }

    if (hasEntrySupport) {
      // Process using FileSystem API (supports folders)
      const entryPromises: Promise<void>[] = [];
      for (let i = 0; i < items.length; i++) {
        const item = items[i];
        const entry = item.webkitGetAsEntry?.();
        
        if (entry) {
          entryPromises.push(processEntry(entry));
        }
      }
      await Promise.all(entryPromises);
    } else {
      // Fallback: use dataTransfer.files directly (no folder support)
      for (let i = 0; i < dataTransferFiles.length; i++) {
        const file = dataTransferFiles[i];
        if (file && isImageFile(file)) {
          files.push(file);
        }
      }
    }

    if (files.length > 0) {
      // Extract folder name from first file
      if (files[0].webkitRelativePath) {
        const pathParts = files[0].webkitRelativePath.split("/");
        if (pathParts.length > 1) {
          setFolderName(pathParts[0]);
        }
      }
      
      await processFiles(files);
    }
  }, [processFiles, setFolderName]);

  /**
   * Handle file input change
   */
  const handleFileChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    if (e.target.files && e.target.files.length > 0) {
      processFiles(e.target.files);
    }
    // Reset input
    e.target.value = "";
  }, [processFiles]);

  /**
   * Handle sprite click
   */
  const handleSpriteClick = useCallback((id: string, e: React.MouseEvent) => {
    selectSprite(id, e.ctrlKey || e.metaKey);
  }, [selectSprite]);

  /**
   * Handle clear all
   */
  const handleClear = useCallback(() => {
    clearSprites();
    setFolderName("");
  }, [clearSprites, setFolderName]);

  /**
   * Scroll selected item into view
   */
  useEffect(() => {
    if (selectedSpriteIds.length === 1) {
      const selectedId = selectedSpriteIds[0];
      const element = document.getElementById(`sprite-${selectedId}`);
      if (element) {
        element.scrollIntoView({ behavior: "smooth", block: "nearest" });
      }
    }
  }, [selectedSpriteIds]);

  return (
    <div 
      ref={dropZoneRef}
      className="flex h-full flex-col overflow-hidden rounded-2xl border border-white/[0.08] bg-[#1c1c1e]/80 backdrop-blur-xl shadow-xl"
      onDragEnter={handleDragEnter}
      onDragLeave={handleDragLeave}
      onDragOver={handleDragOver}
      onDrop={handleDrop}
    >
      {/* Header */}
      <div className="flex items-center justify-between border-b border-white/[0.06] px-4 py-3">
        <div className="flex items-center gap-2">
          <button
            onClick={() => setIsExpanded(!isExpanded)}
            className="text-muted-foreground hover:text-foreground transition-colors"
          >
            {isExpanded ? (
              <ChevronDown className="h-4 w-4" />
            ) : (
              <ChevronRight className="h-4 w-4" />
            )}
          </button>
          {folderName ? (
            <FolderOpen className="h-4 w-4 text-primary" />
          ) : (
            <Folder className="h-4 w-4 text-muted-foreground" />
          )}
          <span className="text-sm font-medium truncate max-w-[120px]">
            {folderName || t("tools.textureAtlas.sprites") || "精灵"}
          </span>
          {sprites.length > 0 && (
            <span className="text-xs text-muted-foreground">
              ({sprites.length})
            </span>
          )}
        </div>
        {sprites.length > 0 && (
          <Button
            variant="ghost"
            size="icon"
            className="h-7 w-7 hover:bg-white/[0.06]"
            onClick={handleClear}
          >
            <Trash2 className="h-3.5 w-3.5" />
          </Button>
        )}
      </div>

      {/* File list */}
      <AnimatePresence>
        {isExpanded && (
          <motion.div
            initial={{ height: 0 }}
            animate={{ height: "auto" }}
            exit={{ height: 0 }}
            className="flex-1 overflow-hidden"
          >
            <div className="h-full overflow-y-auto scrollbar-thin scrollbar-thumb-white/10 scrollbar-track-transparent">
              {sprites.length > 0 ? (
                <div className="space-y-1 p-2">
                  {sprites.map((sprite, index) => (
                    <motion.div
                      key={sprite.id}
                      id={`sprite-${sprite.id}`}
                      initial={{ opacity: 0, x: -10 }}
                      animate={{ opacity: 1, x: 0 }}
                      exit={{ opacity: 0, x: -10 }}
                      transition={{ delay: index * 0.02 }}
                      onClick={(e) => handleSpriteClick(sprite.id, e)}
                      className={`
                        group flex items-center gap-2.5 rounded-xl px-2.5 py-2 cursor-pointer
                        transition-all duration-150 hover:bg-white/[0.06]
                        ${selectedSpriteIds.includes(sprite.id) ? "bg-primary/15 ring-1 ring-primary/30" : ""}
                      `}
                    >
                      {/* Thumbnail */}
                      <div className="relative h-9 w-9 shrink-0 overflow-hidden rounded-lg border border-white/[0.08] bg-black/30">
                        <canvas
                          ref={(canvas) => {
                            if (canvas && sprite.image) {
                              const ctx = canvas.getContext("2d");
                              if (ctx) {
                                canvas.width = 36;
                                canvas.height = 36;
                                
                                // Calculate aspect ratio fit
                                const scale = Math.min(36 / sprite.width, 36 / sprite.height);
                                const w = sprite.width * scale;
                                const h = sprite.height * scale;
                                const x = (36 - w) / 2;
                                const y = (36 - h) / 2;
                                
                                ctx.clearRect(0, 0, 36, 36);
                                ctx.drawImage(sprite.image, x, y, w, h);
                              }
                            }
                          }}
                          className="h-full w-full"
                        />
                      </div>

                      {/* Info */}
                      <div className="min-w-0 flex-1">
                        <p className="truncate text-xs font-medium">{sprite.name}</p>
                        <p className="text-[10px] text-muted-foreground/70">
                          {sprite.width} × {sprite.height}
                        </p>
                      </div>

                      {/* Remove button */}
                      <Button
                        variant="ghost"
                        size="icon"
                        className="h-6 w-6 opacity-0 group-hover:opacity-100 hover:bg-white/[0.08] transition-opacity"
                        onClick={(e) => {
                          e.stopPropagation();
                          removeSprite(sprite.id);
                        }}
                      >
                        <X className="h-3 w-3" />
                      </Button>
                    </motion.div>
                  ))}
                </div>
              ) : (
                /* Empty state / Drop zone */
                <div className="flex h-full min-h-[200px] flex-col items-center justify-center p-4 text-center">
                  {isDragging ? (
                    <motion.div
                      initial={{ scale: 0.9, opacity: 0 }}
                      animate={{ scale: 1, opacity: 1 }}
                      className="flex flex-col items-center"
                    >
                      <div className="mb-3 flex h-14 w-14 items-center justify-center rounded-2xl bg-primary/20">
                        <Upload className="h-7 w-7 text-primary" />
                      </div>
                      <p className="text-sm font-medium text-primary">
                        {t("uploader.dropActive") || "释放文件即可上传"}
                      </p>
                    </motion.div>
                  ) : isLoading ? (
                    <div className="flex flex-col items-center">
                      <div className="mb-3 h-8 w-8 animate-spin rounded-full border-2 border-primary border-t-transparent" />
                      <p className="text-xs text-muted-foreground">
                        {t("common.loading") || "加载中..."}
                      </p>
                    </div>
                  ) : (
                    <>
                      <div className="mb-3 flex h-14 w-14 items-center justify-center rounded-2xl bg-white/[0.04]">
                        <ImageIcon className="h-7 w-7 text-muted-foreground/60" />
                      </div>
                      <p className="mb-1 text-sm font-medium">
                        {t("atlas.dropSprites") || "拖拽精灵图到这里"}
                      </p>
                      <p className="mb-4 text-xs text-muted-foreground/60">
                        {t("atlas.supportFolder") || "支持拖拽文件夹上传"}
                      </p>
                      <div className="flex flex-col gap-2 w-full px-2">
                        <Button
                          variant="outline"
                          size="sm"
                          className="w-full rounded-xl border-white/[0.08] hover:bg-white/[0.06]"
                          onClick={() => fileInputRef.current?.click()}
                        >
                          <ImageIcon className="mr-1.5 h-3.5 w-3.5" />
                          {t("atlas.selectFiles") || "选择文件"}
                        </Button>
                        <Button
                          variant="outline"
                          size="sm"
                          className="w-full rounded-xl border-white/[0.08] hover:bg-white/[0.06]"
                          onClick={() => folderInputRef.current?.click()}
                        >
                          <Folder className="mr-1.5 h-3.5 w-3.5" />
                          {t("atlas.selectFolder") || "选择文件夹"}
                        </Button>
                      </div>
                    </>
                  )}
                </div>
              )}
            </div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* Hidden file inputs */}
      <input
        ref={fileInputRef}
        type="file"
        multiple
        accept="image/png,image/jpeg,image/webp,image/gif,image/bmp"
        className="hidden"
        onChange={handleFileChange}
      />
      <input
        ref={folderInputRef}
        type="file"
        multiple
        accept="image/png,image/jpeg,image/webp,image/gif,image/bmp"
        // @ts-expect-error - webkitdirectory is not in the type definition
        webkitdirectory="true"
        className="hidden"
        onChange={handleFileChange}
      />

      {/* Drag overlay */}
      <AnimatePresence>
        {isDragging && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="absolute inset-0 z-50 flex items-center justify-center bg-primary/10 backdrop-blur-sm"
          >
            <div className="rounded-lg border-2 border-dashed border-primary bg-background/80 px-8 py-6 text-center">
              <Upload className="mx-auto mb-2 h-8 w-8 text-primary" />
              <p className="font-medium text-primary">
                {t("uploader.dropActive") || "释放文件即可上传"}
              </p>
            </div>
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
}
