"use client";

/**
 * FileDropzone — 通用拖放 / 點擊選檔元件
 *
 * Phase 0.8 conversion (見 .autoflow/03-design/wireframes/wireframe-conversion.md §4.1)
 *
 * 設計目標：
 *   - 同時被「來源模型」（單檔，accept=.onnx,.tflite）與「Reference images」（多檔，accept=image/*）使用
 *   - 拖放與點擊兩種互動都觸發同一個 `onSelect`（呼叫端拿到 File[]，再依 multiple 與否處理）
 *   - 已選檔的呈現由呼叫端負責（這裡只做「未選」的 dropzone 視覺；選了之後呼叫端會 hide 這個元件，改顯示 chips / list）
 *
 * a11y：
 *   - dropzone 本體是 `<label>` 包 `<input type="file" class="sr-only">`，鍵盤 Tab + Enter / Space 直接觸發 file picker（瀏覽器原生）
 *   - 整體區塊用 `aria-label` 描述功能，dragover 時加 `aria-busy="true"`
 *   - 不用 role="button"，避免覆蓋 label/input 的原生語義
 *
 * F-T4 不負責的：
 *   - 檔案驗證（副檔名 / size）由呼叫端處理 — 這裡只是 UI 殼
 *   - 拖放動畫（visualOnly hint dragover 高亮即可）
 */

import { Upload } from "lucide-react";
import {
  type DragEvent,
  type ReactNode,
  useCallback,
  useId,
  useState,
} from "react";

import { cn } from "@/lib/utils";

interface FileDropzoneProps {
  /** `<input accept>` — `.onnx,.tflite` 或 `image/*` 之類 */
  accept: string;
  /** 是否允許多檔（ref images 用） */
  multiple?: boolean;
  /** 主要文字（拖放區大字） — 例：「拖曳 .onnx / .tflite 到此處」 */
  primaryLabel: string;
  /** 「或」之類連接文字，不傳則不顯示 */
  orLabel?: string;
  /** 點擊按鈕文字 — 例：「選擇檔案」 */
  browseLabel: string;
  /** 下方 hint — 例：「支援格式：.onnx · .tflite · 最大 500 MB」 */
  hint?: string;
  /** 拖放或選檔後 callback；總是傳 File[]（呼叫端再依 multiple 處理） */
  onSelect: (files: File[]) => void;
  /** disabled 時整塊變灰並擋互動 */
  disabled?: boolean;
  /** 整塊高度；ref images dropzone 比 source dropzone 矮 */
  size?: "default" | "compact";
  /** 自訂 testid，方便測試區分多個 dropzone */
  "data-testid"?: string;
  /** 給 form label 用的 aria-describedby（指向錯誤訊息 id） */
  errorId?: string;
  /** 外部 className override */
  className?: string;
  /** 額外 children（理論上不用，但保留） */
  children?: ReactNode;
}

export function FileDropzone({
  accept,
  multiple = false,
  primaryLabel,
  orLabel,
  browseLabel,
  hint,
  onSelect,
  disabled = false,
  size = "default",
  "data-testid": dataTestId,
  errorId,
  className,
  children,
}: FileDropzoneProps) {
  const inputId = useId();
  const [isDragOver, setIsDragOver] = useState(false);

  const handleFiles = useCallback(
    (fileList: FileList | null) => {
      if (!fileList || fileList.length === 0) return;
      onSelect(Array.from(fileList));
    },
    [onSelect],
  );

  const handleDragOver = useCallback(
    (e: DragEvent<HTMLLabelElement>) => {
      if (disabled) return;
      e.preventDefault();
      // 只有在 dataTransfer 帶檔案時才高亮（避免拖文字 / link 也觸發）
      if (e.dataTransfer.types.includes("Files")) {
        setIsDragOver(true);
      }
    },
    [disabled],
  );

  const handleDragLeave = useCallback(() => {
    setIsDragOver(false);
  }, []);

  const handleDrop = useCallback(
    (e: DragEvent<HTMLLabelElement>) => {
      if (disabled) return;
      e.preventDefault();
      setIsDragOver(false);
      handleFiles(e.dataTransfer.files);
    },
    [disabled, handleFiles],
  );

  const heightCls = size === "compact" ? "min-h-20 py-4" : "min-h-32 py-6";

  return (
    <label
      htmlFor={inputId}
      data-testid={dataTestId}
      data-drag-over={isDragOver ? "true" : undefined}
      aria-label={primaryLabel}
      aria-busy={isDragOver || undefined}
      aria-describedby={errorId}
      onDragOver={handleDragOver}
      onDragEnter={handleDragOver}
      onDragLeave={handleDragLeave}
      onDrop={handleDrop}
      className={cn(
        "bg-muted/40 hover:bg-muted/60 border-input flex w-full cursor-pointer flex-col items-center justify-center gap-2 rounded-md border-2 border-dashed px-4 text-center transition-colors",
        heightCls,
        isDragOver && "border-primary bg-primary/5",
        disabled && "cursor-not-allowed opacity-60 hover:bg-muted/40",
        className,
      )}
    >
      <Upload aria-hidden="true" className="text-muted-foreground size-5" />
      <div className="text-foreground text-sm font-medium">{primaryLabel}</div>
      <div className="text-muted-foreground flex items-center gap-2 text-xs">
        {orLabel ? <span>{orLabel}</span> : null}
        <span className="text-primary underline-offset-2 group-hover:underline">
          {browseLabel}
        </span>
      </div>
      {hint ? (
        <p className="text-muted-foreground text-xs">{hint}</p>
      ) : null}
      {children}

      {/* 真正的 file input — 用 sr-only 讓鍵盤 / 螢幕閱讀器仍可使用 */}
      <input
        id={inputId}
        type="file"
        accept={accept}
        multiple={multiple}
        disabled={disabled}
        className="sr-only"
        onChange={(e) => {
          handleFiles(e.target.files);
          // reset value 讓同一檔案重選也會觸發 onChange
          e.target.value = "";
        }}
      />
    </label>
  );
}
