import { useEffect, useRef, useState } from "react";
import type { ChangeEvent, DragEvent as ReactDragEvent } from "react";
import type { ChatAttachment } from "@qjclaw/shared-types";
import {
  COMPOSER_ATTACHMENT_ACCEPT,
  IMAGE_ATTACHMENT_EXTENSIONS,
  SUPPORTED_ATTACHMENT_EXTENSIONS
} from "../../lib/constants";
import { desktopApi } from "../../lib/desktop-api";

export type ComposerAttachmentMode = "image-only" | "all-supported";

interface UseComposerAttachmentsOptions {
  mode: ComposerAttachmentMode;
  setErrorText: (value: string) => void;
}

const COMPOSER_IMAGE_ATTACHMENT_ACCEPT = [...IMAGE_ATTACHMENT_EXTENSIONS].join(",");
const HOME_IMAGE_ATTACHMENT_ERROR = "首页对话仅支持上传图片附件。";
const SUPPORTED_ATTACHMENT_ERROR = "Supported attachments: images, MP3, PDF, PPT, Excel, Word, CSV, TXT, Markdown, and JSON.";

function resolveExtension(name: string, localPath: string): string {
  const candidate = name || localPath;
  const index = candidate.lastIndexOf(".");
  return index >= 0 ? candidate.slice(index).toLowerCase() : "";
}

function isImageAttachment(attachment: ChatAttachment): boolean {
  const mimeType = attachment.mimeType?.trim().toLowerCase() ?? "";
  const extension = resolveExtension(attachment.name, attachment.localPath);
  return attachment.kind === "image" || mimeType.startsWith("image/") || IMAGE_ATTACHMENT_EXTENSIONS.has(extension);
}

export function useComposerAttachments({ mode, setErrorText }: UseComposerAttachmentsOptions) {
  const [composerAttachments, setComposerAttachments] = useState<ChatAttachment[]>([]);
  const [isComposerDragOver, setIsComposerDragOver] = useState(false);
  const attachmentInputRef = useRef<HTMLInputElement | null>(null);
  const composerDragDepthRef = useRef(0);
  const composerModeRef = useRef(mode);
  const attachmentAccept = mode === "image-only" ? COMPOSER_IMAGE_ATTACHMENT_ACCEPT : COMPOSER_ATTACHMENT_ACCEPT;

  useEffect(() => {
    composerModeRef.current = mode;
  }, [mode]);

  useEffect(() => {
    if (mode !== "image-only") {
      return;
    }

    const filtered = composerAttachments.filter((attachment) => isImageAttachment(attachment));
    if (filtered.length === composerAttachments.length) {
      return;
    }

    setErrorText(HOME_IMAGE_ATTACHMENT_ERROR);
    setComposerAttachments(filtered);
  }, [composerAttachments, mode, setErrorText]);

  function resolveComposerAttachmentKind(file: File, localPath: string): ChatAttachment["kind"] | null {
    if (file.type.startsWith("image/")) {
      return "image";
    }

    const extension = resolveExtension(file.name, localPath);
    if (IMAGE_ATTACHMENT_EXTENSIONS.has(extension)) {
      return "image";
    }
    if (SUPPORTED_ATTACHMENT_EXTENSIONS.has(extension)) {
      return "file";
    }
    return null;
  }

  function appendComposerAttachments(nextAttachments: ChatAttachment[]) {
    setComposerAttachments((current) => {
      const merged = [...current];
      const seen = new Set(current.map((attachment) => attachment.localPath.toLowerCase()));
      for (const attachment of nextAttachments) {
        const key = attachment.localPath.toLowerCase();
        if (seen.has(key)) {
          continue;
        }
        seen.add(key);
        merged.push(attachment);
      }
      return merged;
    });
  }

  function clearComposerAttachment() {
    setErrorText("");
    setComposerAttachments([]);
    if (attachmentInputRef.current) {
      attachmentInputRef.current.value = "";
    }
  }

  function removeComposerAttachment(localPath: string) {
    setComposerAttachments((current) => current.filter((attachment) => attachment.localPath !== localPath));
  }

  function acceptComposerAttachmentFile(file: File) {
    const kind = resolveComposerAttachmentKind(file, file.name);
    if (mode === "image-only" && kind !== "image") {
      setErrorText(HOME_IMAGE_ATTACHMENT_ERROR);
      return;
    }

    const localPath = (file as File & { path?: string }).path?.trim();
    if (!localPath) {
      setErrorText("The desktop client did not provide a local file path, so this attachment cannot be sent into the project workspace.");
      return;
    }

    if (!kind) {
      setErrorText(SUPPORTED_ATTACHMENT_ERROR);
      return;
    }

    setErrorText("");
    appendComposerAttachments([{
      kind,
      name: file.name || localPath.split(/[\\/]/).pop() || "attachment",
      mimeType: file.type || "application/octet-stream",
      localPath
    }]);
  }

  function handleComposerDragEnter(event: ReactDragEvent<HTMLFormElement>) {
    if (!event.dataTransfer?.files?.length) {
      return;
    }

    event.preventDefault();
    composerDragDepthRef.current += 1;
    setIsComposerDragOver(true);
  }

  function handleComposerDragOver(event: ReactDragEvent<HTMLFormElement>) {
    if (!event.dataTransfer?.files?.length) {
      return;
    }

    event.preventDefault();
    event.dataTransfer.dropEffect = "copy";
  }

  function handleComposerDragLeave(event: ReactDragEvent<HTMLFormElement>) {
    if (!event.dataTransfer?.files?.length) {
      return;
    }

    event.preventDefault();
    composerDragDepthRef.current = Math.max(0, composerDragDepthRef.current - 1);
    if (composerDragDepthRef.current === 0) {
      setIsComposerDragOver(false);
    }
  }

  function handleComposerDrop(event: ReactDragEvent<HTMLFormElement>) {
    if (!event.dataTransfer?.files?.length) {
      return;
    }

    event.preventDefault();
    composerDragDepthRef.current = 0;
    setIsComposerDragOver(false);
    const files = Array.from(event.dataTransfer.files);
    for (const file of files) {
      acceptComposerAttachmentFile(file);
    }
  }

  async function openAttachmentPicker() {
    if (window.qjcDesktop) {
      if (composerModeRef.current === "image-only") {
        const attachment = await desktopApi.chat.pickImageAttachment();
        if (!attachment) {
          return;
        }
        if (composerModeRef.current === "image-only" && !isImageAttachment(attachment)) {
          setErrorText(HOME_IMAGE_ATTACHMENT_ERROR);
          return;
        }
        setErrorText("");
        appendComposerAttachments([attachment]);
        return;
      }

      const attachments = await desktopApi.chat.pickAttachments();
      if (!attachments.length) {
        return;
      }
      setErrorText("");
      appendComposerAttachments(attachments);
      return;
    }

    attachmentInputRef.current?.click();
  }

  function handleAttachmentSelection(event: ChangeEvent<HTMLInputElement>) {
    const files = event.target.files ? Array.from(event.target.files) : [];
    if (!files.length) {
      return;
    }

    for (const file of files) {
      acceptComposerAttachmentFile(file);
    }
    event.target.value = "";
  }

  return {
    attachmentInputRef,
    attachmentAccept,
    composerAttachments,
    isComposerDragOver,
    clearComposerAttachment,
    removeComposerAttachment,
    openAttachmentPicker,
    handleAttachmentSelection,
    handleComposerDragEnter,
    handleComposerDragOver,
    handleComposerDragLeave,
    handleComposerDrop
  };
}
