import React, { useEffect, useMemo, useRef, useState } from "react";
import { Button } from "./ui/button";
import {
  Upload,
  File as FileIcon,
  X,
  FileText,
  Presentation,
  Image as ImageIcon,
} from "lucide-react";
import { Card } from "./ui/card";
import { Badge } from "./ui/badge";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "./ui/select";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "./ui/dialog";
import type { UploadedFile, FileType } from "../App";

interface FileUploadAreaProps {
  uploadedFiles: UploadedFile[];
  onFileUpload: (files: File[]) => void;
  onRemoveFile: (index: number) => void;
  onFileTypeChange: (index: number, type: FileType) => void;
  disabled?: boolean;
}

interface PendingFile {
  file: File;
  type: FileType;
}

const ACCEPT_EXTS = [".pdf", ".docx", ".pptx", ".png", ".jpg", ".jpeg", ".webp", ".gif"];
const ACCEPT_ATTR = ".pdf,.docx,.pptx,.png,.jpg,.jpeg,.webp,.gif";

function isImageFile(file: File) {
  if (file.type?.startsWith("image/")) return true;
  const n = file.name.toLowerCase();
  return [".png", ".jpg", ".jpeg", ".webp", ".gif"].some((ext) => n.endsWith(ext));
}

function getFileIcon(filename: string) {
  const lower = filename.toLowerCase();
  if (lower.endsWith(".pdf")) return FileText;
  if (lower.endsWith(".pptx")) return Presentation;
  if (lower.endsWith(".docx")) return FileIcon;
  if ([".png", ".jpg", ".jpeg", ".webp", ".gif"].some((ext) => lower.endsWith(ext)))
    return ImageIcon;
  return FileIcon;
}

function formatFileSize(bytes: number) {
  if (bytes < 1024) return bytes + " B";
  if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB";
  return (bytes / (1024 * 1024)).toFixed(1) + " MB";
}

export function FileUploadArea({
  uploadedFiles,
  onFileUpload,
  onRemoveFile,
  onFileTypeChange,
  disabled = false,
}: FileUploadAreaProps) {
  const [isDragging, setIsDragging] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const [pendingFiles, setPendingFiles] = useState<PendingFile[]>([]);
  const [showTypeDialog, setShowTypeDialog] = useState(false);

  // ===== objectURL cache（更稳：不用 state，避免时序问题）=====
  const urlCacheRef = useRef<Map<string, string>>(new Map());

  const fingerprint = (f: File) => `${f.name}::${f.size}::${f.lastModified}`;

  const allFiles = useMemo(() => {
    return [
      ...uploadedFiles.map((u) => u.file),
      ...pendingFiles.map((p) => p.file),
    ];
  }, [uploadedFiles, pendingFiles]);

  // 维护 cache：只保留当前需要的 image url；移除的立即 revoke
  useEffect(() => {
    const need = new Set<string>();
    for (const f of allFiles) {
      if (!isImageFile(f)) continue;
      need.add(fingerprint(f));
    }

    // revoke removed
    for (const [key, url] of urlCacheRef.current.entries()) {
      if (!need.has(key)) {
        try {
          URL.revokeObjectURL(url);
        } catch {
          // ignore
        }
        urlCacheRef.current.delete(key);
      }
    }

    // create missing
    for (const f of allFiles) {
      if (!isImageFile(f)) continue;
      const key = fingerprint(f);
      if (!urlCacheRef.current.has(key)) {
        urlCacheRef.current.set(key, URL.createObjectURL(f));
      }
    }
  }, [allFiles]);

  // unmount：全部 revoke
  useEffect(() => {
    return () => {
      for (const url of urlCacheRef.current.values()) {
        try {
          URL.revokeObjectURL(url);
        } catch {
          // ignore
        }
      }
      urlCacheRef.current.clear();
    };
  }, []);

  const getPreviewUrl = (file: File) => {
    const key = fingerprint(file);
    return urlCacheRef.current.get(key);
  };

  const filterSupportedFiles = (files: File[]) => {
    return files.filter((file) => {
      if (isImageFile(file)) return true;
      const lower = file.name.toLowerCase();
      return [".pdf", ".docx", ".pptx"].some((ext) => lower.endsWith(ext));
    });
  };

  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault();
    if (!disabled) setIsDragging(true);
  };

  const handleDragLeave = () => setIsDragging(false);

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    setIsDragging(false);
    if (disabled) return;

    const files = filterSupportedFiles(Array.from(e.dataTransfer.files));
    if (files.length > 0) {
      setPendingFiles(files.map((file) => ({ file, type: "other" as FileType })));
      setShowTypeDialog(true);
    }
  };

  const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = filterSupportedFiles(Array.from(e.target.files || []));
    if (files.length > 0) {
      setPendingFiles(files.map((file) => ({ file, type: "other" as FileType })));
      setShowTypeDialog(true);
    }
    e.target.value = "";
  };

  const handleConfirmUpload = () => {
    onFileUpload(pendingFiles.map((pf) => pf.file));

    const startIndex = uploadedFiles.length;
    pendingFiles.forEach((pf, idx) => {
      setTimeout(() => {
        onFileTypeChange(startIndex + idx, pf.type);
      }, 0);
    });

    setPendingFiles([]);
    setShowTypeDialog(false);
  };

  const handleCancelUpload = () => {
    setPendingFiles([]);
    setShowTypeDialog(false);
  };

  const handlePendingFileTypeChange = (index: number, type: FileType) => {
    setPendingFiles((prev) => prev.map((pf, i) => (i === index ? { ...pf, type } : pf)));
  };

  const renderLeading = (file: File) => {
    if (isImageFile(file)) {
      const src = getPreviewUrl(file);
      return (
        <div className="h-12 w-12 rounded-md overflow-hidden bg-background border border-border flex-shrink-0">
          {src ? (
            <img
              src={src}
              alt={file.name}
              className="h-full w-full object-cover"
              draggable={false}
            />
          ) : (
            <div className="h-full w-full flex items-center justify-center text-muted-foreground">
              <ImageIcon className="h-5 w-5" />
            </div>
          )}
        </div>
      );
    }

    const Icon = getFileIcon(file.name);
    return <Icon className="h-5 w-5 text-muted-foreground flex-shrink-0" />;
  };

  return (
    <Card className="p-4 space-y-3">
      <div className="flex items-center justify-between">
        <h4 className="text-sm">Course Materials</h4>
        {uploadedFiles.length > 0 && (
          <Badge variant="secondary">{uploadedFiles.length} file(s)</Badge>
        )}
      </div>

      {/* Upload Area */}
      <div
        onDragOver={handleDragOver}
        onDragLeave={handleDragLeave}
        onDrop={handleDrop}
        className={[
          "border-2 border-dashed rounded-lg p-4 text-center transition-colors",
          isDragging ? "border-primary bg-accent" : "border-border",
          disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer",
        ].join(" ")}
        onClick={() => !disabled && fileInputRef.current?.click()}
      >
        <Upload className="h-6 w-6 mx-auto mb-2 text-muted-foreground" />
        <p className="text-sm text-muted-foreground mb-1">
          {disabled ? "Please log in to upload" : "Drop files or click to upload"}
        </p>
        <p className="text-xs text-muted-foreground">{ACCEPT_EXTS.join(", ")}</p>

        <input
          ref={fileInputRef}
          type="file"
          multiple
          accept={ACCEPT_ATTR}
          onChange={handleFileSelect}
          className="hidden"
          disabled={disabled}
        />
      </div>

      {/* Uploaded Files List */}
      {uploadedFiles.length > 0 && (
        <div className="space-y-3 max-h-64 overflow-y-auto">
          {uploadedFiles.map((uploadedFile, index) => {
            const f = uploadedFile.file;
            return (
              <div key={index} className="p-3 bg-muted rounded-md space-y-2">
                <div className="flex items-center gap-3 group">
                  {renderLeading(f)}

                  <div className="flex-1 min-w-0">
                    <p className="text-sm truncate">{f.name}</p>
                    <p className="text-xs text-muted-foreground">{formatFileSize(f.size)}</p>
                  </div>

                  <Button
                    variant="ghost"
                    size="icon"
                    className="h-6 w-6 opacity-0 group-hover:opacity-100 transition-opacity"
                    onClick={(e) => {
                      e.stopPropagation();
                      onRemoveFile(index);
                    }}
                    title="Remove"
                  >
                    <X className="h-3 w-3" />
                  </Button>
                </div>

                <div className="space-y-1">
                  <label className="text-xs text-muted-foreground">File Type</label>
                  <Select
                    value={uploadedFile.type}
                    onValueChange={(value) => onFileTypeChange(index, value as FileType)}
                  >
                    <SelectTrigger className="h-8 text-xs">
                      <SelectValue />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value="syllabus">Syllabus</SelectItem>
                      <SelectItem value="lecture-slides">Lecture Slides / PPT</SelectItem>
                      <SelectItem value="literature-review">Literature Review / Paper</SelectItem>
                      <SelectItem value="other">Other Course Document</SelectItem>
                    </SelectContent>
                  </Select>
                </div>
              </div>
            );
          })}
        </div>
      )}

      {/* Type Selection Dialog */}
      {showTypeDialog && (
        <Dialog open={showTypeDialog} onOpenChange={setShowTypeDialog}>
          <DialogContent className="sm:max-w-[425px]">
            <DialogHeader>
              <DialogTitle>Select File Types</DialogTitle>
              <DialogDescription>
                Please select the type for each file you are uploading.
              </DialogDescription>
            </DialogHeader>

            <div className="space-y-3 max-h-64 overflow-y-auto">
              {pendingFiles.map((pendingFile, index) => {
                const f = pendingFile.file;
                return (
                  <div key={index} className="p-3 bg-muted rounded-md space-y-2">
                    <div className="flex items-center gap-3">
                      {renderLeading(f)}
                      <div className="flex-1 min-w-0">
                        <p className="text-sm truncate">{f.name}</p>
                        <p className="text-xs text-muted-foreground">{formatFileSize(f.size)}</p>
                      </div>
                    </div>

                    <div className="space-y-1">
                      <label className="text-xs text-muted-foreground">File Type</label>
                      <Select
                        value={pendingFile.type}
                        onValueChange={(value) => handlePendingFileTypeChange(index, value as FileType)}
                      >
                        <SelectTrigger className="h-8 text-xs">
                          <SelectValue />
                        </SelectTrigger>
                        <SelectContent>
                          <SelectItem value="syllabus">Syllabus</SelectItem>
                          <SelectItem value="lecture-slides">Lecture Slides / PPT</SelectItem>
                          <SelectItem value="literature-review">Literature Review / Paper</SelectItem>
                          <SelectItem value="other">Other Course Document</SelectItem>
                        </SelectContent>
                      </Select>
                    </div>
                  </div>
                );
              })}
            </div>

            <DialogFooter>
              <Button variant="outline" onClick={handleCancelUpload}>
                Cancel
              </Button>
              <Button onClick={handleConfirmUpload}>Upload</Button>
            </DialogFooter>
          </DialogContent>
        </Dialog>
      )}
    </Card>
  );
}
