/**
 * TipTap 변수 태그 확장
 * 본문 내에서 {{변수명}} 형태의 변수를 시각적 태그로 표시
 */

import { Node, mergeAttributes } from "@tiptap/core";
import { ReactNodeViewRenderer } from "@tiptap/react";

// 변수 태그 노드 타입
export interface VariableTagOptions {
  HTMLAttributes: Record<string, any>;
}

// 변수 태그 속성
export interface VariableTagAttributes {
  variableName: string; // 실제 변수명 (예: customerName)
  displayName: string; // 표시명 (예: 고객명)
}

/**
 * 변수 태그 TipTap 확장
 */
export const VariableTagExtension = Node.create<VariableTagOptions>({
  name: "variableTag",

  group: "inline",

  inline: true,

  // atom: true로 설정하면 커서가 태그 내부로 들어가지 않음
  atom: true,

  // 선택 가능하도록 설정
  selectable: true,

  // 드래그 가능하도록 설정
  draggable: true,

  addOptions() {
    return {
      HTMLAttributes: {},
    };
  },

  addAttributes() {
    return {
      variableName: {
        default: "",
        parseHTML: (element) => element.getAttribute("data-variable-name"),
        renderHTML: (attributes) => ({
          "data-variable-name": attributes.variableName,
        }),
      },
      displayName: {
        default: "",
        parseHTML: (element) => element.getAttribute("data-display-name"),
        renderHTML: (attributes) => ({
          "data-display-name": attributes.displayName,
        }),
      },
    };
  },

  parseHTML() {
    return [
      {
        tag: 'span[data-type="variable-tag"]',
      },
    ];
  },

  renderHTML({ HTMLAttributes }) {
    return [
      "span",
      mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
        "data-type": "variable-tag",
        class: "variable-tag",
      }),
      HTMLAttributes["data-display-name"] || HTMLAttributes["data-variable-name"],
    ];
  },

  // 키보드 명령어 추가 (Backspace로 삭제)
  addKeyboardShortcuts() {
    return {
      Backspace: () =>
        this.editor.commands.command(({ tr, state }) => {
          let isVariableTag = false;
          const { selection } = state;
          const { empty, anchor } = selection;

          if (!empty) {
            return false;
          }

          state.doc.nodesBetween(anchor - 1, anchor, (node, pos) => {
            if (node.type.name === this.name) {
              isVariableTag = true;
              tr.delete(pos, pos + node.nodeSize);
              return false;
            }
          });

          return isVariableTag;
        }),
    };
  },
});

/**
 * 텍스트를 에디터 JSON으로 변환
 * "안녕하세요, {{customerName}} 님" → TipTap JSON
 */
export function textToEditorContent(
  text: string,
  variableMap: Record<string, string> // { customerName: "고객명" }
): any {
  if (!text) {
    return {
      type: "doc",
      content: [{ type: "paragraph" }],
    };
  }

  const regex = /\{\{(\w+)\}\}/g;
  const content: any[] = [];
  let lastIndex = 0;
  let match;

  while ((match = regex.exec(text)) !== null) {
    // 변수 앞의 일반 텍스트
    if (match.index > lastIndex) {
      const beforeText = text.slice(lastIndex, match.index);
      if (beforeText) {
        content.push({ type: "text", text: beforeText });
      }
    }

    // 변수 태그
    const variableName = match[1];
    const displayName = variableMap[variableName] || variableName;
    content.push({
      type: "variableTag",
      attrs: {
        variableName,
        displayName,
      },
    });

    lastIndex = regex.lastIndex;
  }

  // 마지막 텍스트
  if (lastIndex < text.length) {
    content.push({ type: "text", text: text.slice(lastIndex) });
  }

  // content가 비어있으면 빈 paragraph 추가
  if (content.length === 0) {
    return {
      type: "doc",
      content: [{ type: "paragraph" }],
    };
  }

  return {
    type: "doc",
    content: [
      {
        type: "paragraph",
        content,
      },
    ],
  };
}

/**
 * 에디터 JSON을 텍스트로 변환
 * TipTap JSON → "안녕하세요, {{customerName}} 님"
 */
export function editorContentToText(json: any): string {
  if (!json || !json.content) {
    return "";
  }

  let result = "";

  const processNode = (node: any) => {
    if (node.type === "text") {
      result += node.text || "";
    } else if (node.type === "variableTag") {
      result += `{{${node.attrs?.variableName || ""}}}`;
    } else if (node.type === "paragraph") {
      if (node.content) {
        node.content.forEach(processNode);
      }
      result += "\n";
    } else if (node.type === "hardBreak") {
      result += "\n";
    } else if (node.content) {
      node.content.forEach(processNode);
    }
  };

  json.content.forEach(processNode);

  // 마지막 줄바꿈 제거
  return result.replace(/\n$/, "");
}

