import { SendOutlined } from "@ant-design/icons";
import { useRef, type CSSProperties, type Dispatch, type SetStateAction } from "react";
import type { CanvasNodeKind, CanvasPromptMentionOption, CanvasPromptMentionState } from "./canvasTypes";

const MENTION_BOUNDARY_RE = /\s|[，。、；：！？?(){}[\]<>]/;
const EMPTY_MENTION_STYLE: CSSProperties = { opacity: 0.5, pointerEvents: "none" };
const DEFAULT_MENTION_STATE: CanvasPromptMentionState = {
  open: false,
  query: "",
  start: 0,
  caret: 0,
  activeIndex: 0,
};

interface CanvasPromptMentionTextareaProps {
  nodeId: string;
  value: string;
  placeholder: string;
  mentionOptions: CanvasPromptMentionOption[];
  mentionState?: CanvasPromptMentionState;
  onPromptChange: (nodeId: string, prompt: string) => void;
  onMentionStateChange: Dispatch<SetStateAction<Record<string, CanvasPromptMentionState>>>;
  onCloseMention: (nodeId: string) => void;
  onInsertMention: (
    nodeId: string,
    option: CanvasPromptMentionOption,
    textarea: HTMLTextAreaElement | null,
    kind?: CanvasNodeKind,
  ) => void;
  mentionKind?: CanvasNodeKind;
}

export function CanvasPromptMentionTextarea({
  nodeId,
  value,
  placeholder,
  mentionOptions,
  mentionState = DEFAULT_MENTION_STATE,
  onPromptChange,
  onMentionStateChange,
  onCloseMention,
  onInsertMention,
  mentionKind,
}: CanvasPromptMentionTextareaProps) {
  const textareaRef = useRef<HTMLTextAreaElement | null>(null);
  const filteredMentions = mentionState.open
    ? mentionOptions.filter((option) => !mentionState.query || option.searchText.includes(mentionState.query.toLowerCase()))
    : [];

  const handlePromptChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
    const value = event.target.value;
    const caret = event.target.selectionStart || 0;
    onPromptChange(nodeId, value);

    const beforeCaret = value.slice(0, caret);
    const atIndex = beforeCaret.lastIndexOf("@");
    if (atIndex >= 0) {
      const query = beforeCaret.slice(atIndex + 1);
      if (!MENTION_BOUNDARY_RE.test(query) && !query.includes(" ")) {
        onMentionStateChange((prev) => ({
          ...prev,
          [nodeId]: { open: true, query, start: atIndex, caret, activeIndex: 0 },
        }));
        return;
      }
    }
    onCloseMention(nodeId);
  };

  const handlePromptKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
    if (!mentionState.open || filteredMentions.length === 0) return;
    if (event.key === "ArrowDown") {
      event.preventDefault();
      onMentionStateChange((prev) => ({
        ...prev,
        [nodeId]: { ...mentionState, activeIndex: (mentionState.activeIndex + 1) % filteredMentions.length },
      }));
    } else if (event.key === "ArrowUp") {
      event.preventDefault();
      onMentionStateChange((prev) => ({
        ...prev,
        [nodeId]: {
          ...mentionState,
          activeIndex: (mentionState.activeIndex - 1 + filteredMentions.length) % filteredMentions.length,
        },
      }));
    } else if (event.key === "Enter" || event.key === "Tab") {
      event.preventDefault();
      const option = filteredMentions[mentionState.activeIndex];
      if (option) {
        onInsertMention(nodeId, option, event.currentTarget, mentionKind);
      }
    } else if (event.key === "Escape") {
      event.preventDefault();
      onCloseMention(nodeId);
    }
  };

  const handlePromptSelect = (event: React.SyntheticEvent<HTMLTextAreaElement>) => {
    const caret = event.currentTarget.selectionStart || 0;
    onMentionStateChange((prev) => {
      const current = prev[nodeId];
      if (!current?.open) return prev;
      return { ...prev, [nodeId]: { ...current, caret } };
    });
  };

  return (
    <div className="studio-canvas-text-composer__input-wrap">
      <textarea
        ref={textareaRef}
        value={value}
        onMouseDown={(event) => event.stopPropagation()}
        onChange={handlePromptChange}
        onKeyDown={handlePromptKeyDown}
        onSelect={handlePromptSelect}
        placeholder={placeholder}
      />
      {mentionState.open ? (
        <div className="studio-canvas-mention-panel">
          {filteredMentions.length > 0 ? filteredMentions.map((option, index) => (
            <button
              key={option.token}
              type="button"
              className={`studio-canvas-mention-item${index === mentionState.activeIndex ? " is-active" : ""}`}
              onMouseDown={(event) => {
                event.preventDefault();
                onInsertMention(nodeId, option, textareaRef.current, mentionKind);
              }}
            >
              <span className="studio-canvas-mention-thumb">
                {option.kind === "image" && option.previewUrl ? (
                  <img src={option.previewUrl} alt="" />
                ) : option.kind === "image" ? "🖼" : option.kind === "video" ? "🎬" : "📝"}
              </span>
              <span className="studio-canvas-mention-label">{option.nodeTitle}</span>
              <span className="studio-canvas-mention-token">{option.token}</span>
            </button>
          )) : (
            <div className="studio-canvas-mention-item" style={EMPTY_MENTION_STYLE}>
              <span className="studio-canvas-mention-label">没有可引用的连接节点</span>
            </div>
          )}
        </div>
      ) : null}
    </div>
  );
}

interface CanvasTextPromptComposerProps {
  nodeId: string;
  prompt: string;
  canGenerate: boolean;
  isGenerating: boolean;
  mentionOptions: CanvasPromptMentionOption[];
  mentionState?: CanvasPromptMentionState;
  onPromptChange: (nodeId: string, prompt: string) => void;
  onMentionStateChange: Dispatch<SetStateAction<Record<string, CanvasPromptMentionState>>>;
  onCloseMention: (nodeId: string) => void;
  onInsertMention: (
    nodeId: string,
    option: CanvasPromptMentionOption,
    textarea: HTMLTextAreaElement | null,
    kind?: CanvasNodeKind,
  ) => void;
  onGenerate: (nodeId: string) => void | Promise<void>;
}

export function CanvasTextPromptComposer({
  nodeId,
  prompt,
  canGenerate,
  isGenerating,
  mentionOptions,
  mentionState,
  onPromptChange,
  onMentionStateChange,
  onCloseMention,
  onInsertMention,
  onGenerate,
}: CanvasTextPromptComposerProps) {
  return (
    <div className="studio-canvas-text-composer">
      <CanvasPromptMentionTextarea
        nodeId={nodeId}
        value={prompt}
        placeholder="写下你想讲的故事、场景或角色设定。@引用连接的节点"
        mentionOptions={mentionOptions}
        mentionState={mentionState}
        onPromptChange={onPromptChange}
        onMentionStateChange={onMentionStateChange}
        onCloseMention={onCloseMention}
        onInsertMention={onInsertMention}
      />
      <div className="studio-canvas-text-composer__footer">
        <button
          type="button"
          className={`studio-canvas-text-composer__send studio-canvas-generate-button${canGenerate && !isGenerating ? " is-ready" : ""}`}
          title={isGenerating ? "生成中" : "生成"}
          disabled={isGenerating || !canGenerate}
          aria-busy={isGenerating}
          onMouseDown={(event) => {
            event.preventDefault();
            event.stopPropagation();
            if (!isGenerating && canGenerate) {
              void onGenerate(nodeId);
            }
          }}
          onClick={(event) => {
            event.preventDefault();
            event.stopPropagation();
          }}
        >
          <SendOutlined />
        </button>
      </div>
    </div>
  );
}
