"use client";

// attach_file_info 기반 다중 파일 업로드 드롭존 — 도메인 무관 공통 컴포넌트.
//
// 운영판 wace `fnc_setFileDropZone` (common.js) + `fn_fileCallback2` +
// `fileDelete` 흐름 1:1.
//
// 백엔드:
//   - GET    /api/files?targetObjid=&docType=    (wace getFileList.do)
//   - POST   /api/files/upload                   (wace fileUploadProc.do)
//   - DELETE /api/files/:objid                   (wace deleteFileInfo.do)
//   - GET    /api/files/download/:objid          (wace fnc_downloadFile)
//
// 사용처 예시:
//   - 개발관리 PART CAD Data (3D_CAD / 2D_DRAWING_CAD / 2D_PDF_CAD)
//   - 향후 ERP/ECR/생산실적 등 attach_file_info 쓰는 어떤 화면이든 그대로 재사용.
//
// 호출자가 doc_type / doc_type_name 만 지정하면 도메인 독립.

import React, {
  useCallback,
  useEffect,
  useRef,
  useState,
  DragEvent,
  ChangeEvent,
} from "react";
import { Upload, Download, Trash2, Loader2 } from "lucide-react";
import { toast } from "sonner";
import { apiClient, API_BASE_URL } from "@/lib/api/client";
import { cn } from "@/lib/utils";

export interface AttachFile {
  objid: string;
  realFileName: string;
  savedFileName: string;
  fileSize: number;
  fileExt: string;
  filePath: string;
  docType: string;
  docTypeName: string;
}

interface Props {
  targetObjid: string | null | undefined;
  docType: string;
  docTypeName: string;
  /** 읽기 전용 — 드롭존/삭제 숨김, 다운로드만 허용 */
  readOnly?: boolean;
  /** 파일 선택창 accept 힌트 (예: ".pdf,application/pdf"). 비우면 모든 파일 */
  accept?: string;
  className?: string;
}

export function AttachFileDropZone({
  targetObjid,
  docType,
  docTypeName,
  readOnly = false,
  accept,
  className,
}: Props) {
  const [files, setFiles] = useState<AttachFile[]>([]);
  const [loading, setLoading] = useState(false);
  const [uploading, setUploading] = useState(false);
  const [dragOver, setDragOver] = useState(false);
  const inputRef = useRef<HTMLInputElement | null>(null);

  // ── 목록 조회 (wace fn_fileCallback2) ───────────────────────
  const reload = useCallback(async () => {
    if (!targetObjid) {
      setFiles([]);
      return;
    }
    setLoading(true);
    try {
      const res = await apiClient.get("/files", {
        params: { targetObjid, docType },
      });
      // 응답: { success, files: [...] } — fileController.getFileList
      const raw = (res.data?.files ?? res.data?.data ?? res.data ?? []) as any[];
      const list: AttachFile[] = raw.map((f) => ({
        objid: String(f.objid),
        realFileName: f.realFileName ?? f.real_file_name ?? "",
        savedFileName: f.savedFileName ?? f.saved_file_name ?? "",
        fileSize: Number(f.fileSize ?? f.file_size ?? 0),
        fileExt: f.fileExt ?? f.file_ext ?? "",
        filePath: f.filePath ?? f.file_path ?? "",
        docType: f.docType ?? f.doc_type ?? "",
        docTypeName: f.docTypeName ?? f.doc_type_name ?? "",
      }));
      setFiles(list);
    } catch (e: any) {
      console.error("[AttachFileDropZone] reload 실패", e);
      setFiles([]);
    } finally {
      setLoading(false);
    }
  }, [targetObjid, docType]);

  useEffect(() => {
    reload();
  }, [reload]);

  // ── 업로드 (wace fnc_fileMultiUpload) ───────────────────────
  const uploadFiles = useCallback(
    async (selected: FileList | File[]) => {
      if (!targetObjid) {
        toast.error("저장 대상이 지정되지 않았습니다.");
        return;
      }
      const arr = Array.from(selected);
      if (arr.length === 0) return;

      if (!window.confirm(`${arr.length}개 파일을 업로드 하시겠습니까?`)) {
        return;
      }

      setUploading(true);
      try {
        const fd = new FormData();
        for (const f of arr) fd.append("files", f);
        fd.append("targetObjid", String(targetObjid));
        fd.append("docType", docType);
        fd.append("docTypeName", docTypeName);
        await apiClient.post("/files/upload", fd, {
          headers: { "Content-Type": "multipart/form-data" },
        });
        toast.success(`${arr.length}개 파일이 업로드되었습니다.`);
        await reload();
      } catch (e: any) {
        toast.error(
          e?.response?.data?.message ?? e?.message ?? "업로드 실패"
        );
      } finally {
        setUploading(false);
      }
    },
    [targetObjid, docType, docTypeName, reload]
  );

  // ── 삭제 (wace fileDelete) ──────────────────────────────────
  const removeFile = useCallback(
    async (objid: string) => {
      if (!window.confirm("파일을 삭제하시겠습니까?")) return;
      try {
        await apiClient.delete(`/files/${objid}`);
        await reload();
      } catch (e: any) {
        toast.error(
          e?.response?.data?.message ?? e?.message ?? "삭제 실패"
        );
      }
    },
    [reload]
  );

  // ── 다운로드 ────────────────────────────────────────────────
  const downloadHref = (objid: string) =>
    `${API_BASE_URL}/files/download/${objid}`;

  // ── DnD 이벤트 ──────────────────────────────────────────────
  // macOS Chrome 함정: dropEffect 미지정 시 🚫 거부 커서 + drop 차단.
  const onDragEnter = (e: DragEvent<HTMLDivElement>) => {
    e.preventDefault();
    e.stopPropagation();
    if (readOnly) return;
    if (e.dataTransfer) e.dataTransfer.dropEffect = "copy";
    setDragOver(true);
  };
  const onDragOver = (e: DragEvent<HTMLDivElement>) => {
    e.preventDefault();
    e.stopPropagation();
    if (readOnly) return;
    if (e.dataTransfer) e.dataTransfer.dropEffect = "copy";
    setDragOver(true);
  };
  const onDragLeave = (e: DragEvent<HTMLDivElement>) => {
    e.preventDefault();
    e.stopPropagation();
    setDragOver(false);
  };
  const onDrop = (e: DragEvent<HTMLDivElement>) => {
    e.preventDefault();
    e.stopPropagation();
    setDragOver(false);
    if (readOnly) return;
    const dropped = e.dataTransfer?.files;
    if (dropped && dropped.length > 0) uploadFiles(dropped);
  };

  const onPickClick = () => {
    if (readOnly) return;
    inputRef.current?.click();
  };
  const onPickChange = (e: ChangeEvent<HTMLInputElement>) => {
    const picked = e.target.files;
    if (picked && picked.length > 0) uploadFiles(picked);
    if (inputRef.current) inputRef.current.value = "";
  };

  // ── 렌더 ────────────────────────────────────────────────────
  const showDropZone = !readOnly;
  const showEmptyHint = files.length === 0 && readOnly;

  return (
    <div className={cn("flex flex-col gap-2", className)}>
      {showDropZone && (
        <div
          onDragEnter={onDragEnter}
          onDragOver={onDragOver}
          onDragLeave={onDragLeave}
          onDrop={onDrop}
          onClick={onPickClick}
          className={cn(
            "flex h-[60px] cursor-pointer items-center justify-center gap-2 rounded border-2 border-dashed text-sm transition-colors",
            dragOver
              ? "border-blue-500 bg-blue-50 text-blue-700"
              : "border-muted-foreground/30 bg-muted/20 text-muted-foreground hover:border-blue-400 hover:text-blue-600",
            (!targetObjid || uploading) && "pointer-events-none opacity-60"
          )}
        >
          {uploading ? (
            <>
              <Loader2 className="h-4 w-4 animate-spin" />
              <span>업로드 중...</span>
            </>
          ) : (
            <>
              <Upload className="h-4 w-4" />
              <span>
                {targetObjid
                  ? "여기에 파일을 끌어다 놓거나 클릭하여 선택하세요."
                  : "저장 대상 미지정 — 등록 후 업로드 가능"}
              </span>
            </>
          )}
          <input
            ref={inputRef}
            type="file"
            multiple
            accept={accept}
            className="hidden"
            onChange={onPickChange}
          />
        </div>
      )}

      {loading ? (
        <div className="flex items-center gap-2 px-1 py-2 text-xs text-muted-foreground">
          <Loader2 className="h-3 w-3 animate-spin" /> 목록 로드 중...
        </div>
      ) : files.length > 0 ? (
        <ul className="divide-y rounded border bg-background">
          {files.map((f) => (
            <li
              key={f.objid}
              className="flex items-center justify-between gap-2 px-2 py-1.5 text-sm"
            >
              <a
                href={downloadHref(f.objid)}
                target="_blank"
                rel="noopener noreferrer"
                title={f.realFileName}
                className="flex min-w-0 flex-1 items-center gap-1.5 truncate text-blue-700 hover:underline"
              >
                <Download className="h-3.5 w-3.5 shrink-0" />
                <span className="truncate">{f.realFileName}</span>
              </a>
              <span className="shrink-0 text-xs text-muted-foreground">
                {formatBytes(f.fileSize)}
              </span>
              {!readOnly && (
                <button
                  type="button"
                  onClick={() => removeFile(f.objid)}
                  className="rounded p-1 text-muted-foreground hover:bg-red-50 hover:text-red-600"
                  title="삭제"
                >
                  <Trash2 className="h-3.5 w-3.5" />
                </button>
              )}
            </li>
          ))}
        </ul>
      ) : (
        showEmptyHint && (
          <div className="px-1 py-1 text-xs text-muted-foreground">
            등록된 파일이 없습니다.
          </div>
        )
      )}
    </div>
  );
}

function formatBytes(bytes: number): string {
  if (!bytes || bytes <= 0) return "0 B";
  const units = ["B", "KB", "MB", "GB"];
  let v = bytes;
  let u = 0;
  while (v >= 1024 && u < units.length - 1) {
    v /= 1024;
    u++;
  }
  return `${v.toFixed(u === 0 ? 0 : 1)} ${units[u]}`;
}
