/**
 * CodeHighlight Plugin Extension
 * 代码高亮插件 - 基于 highlight.js
 */

import { PluginExtension } from '../../core/Extension';
import { Plugin, PluginKey } from 'prosemirror-state';
import { Decoration, DecorationSet } from 'prosemirror-view';
import type { Schema } from '../../core/types';
import hljs from 'highlight.js/lib/core';

// 按需导入常用语言
import javascript from 'highlight.js/lib/languages/javascript';
import typescript from 'highlight.js/lib/languages/typescript';
import python from 'highlight.js/lib/languages/python';
import css from 'highlight.js/lib/languages/css';
import xml from 'highlight.js/lib/languages/xml';
import json from 'highlight.js/lib/languages/json';
import markdown from 'highlight.js/lib/languages/markdown';
import bash from 'highlight.js/lib/languages/bash';
import sql from 'highlight.js/lib/languages/sql';
import go from 'highlight.js/lib/languages/go';
import rust from 'highlight.js/lib/languages/rust';
import java from 'highlight.js/lib/languages/java';
import csharp from 'highlight.js/lib/languages/csharp';
import php from 'highlight.js/lib/languages/php';
import ruby from 'highlight.js/lib/languages/ruby';
import yaml from 'highlight.js/lib/languages/yaml';

// 注册语言
hljs.registerLanguage('javascript', javascript);
hljs.registerLanguage('js', javascript);
hljs.registerLanguage('typescript', typescript);
hljs.registerLanguage('ts', typescript);
hljs.registerLanguage('python', python);
hljs.registerLanguage('py', python);
hljs.registerLanguage('css', css);
hljs.registerLanguage('html', xml);
hljs.registerLanguage('xml', xml);
hljs.registerLanguage('json', json);
hljs.registerLanguage('markdown', markdown);
hljs.registerLanguage('md', markdown);
hljs.registerLanguage('bash', bash);
hljs.registerLanguage('sh', bash);
hljs.registerLanguage('shell', bash);
hljs.registerLanguage('sql', sql);
hljs.registerLanguage('go', go);
hljs.registerLanguage('rust', rust);
hljs.registerLanguage('rs', rust);
hljs.registerLanguage('java', java);
hljs.registerLanguage('csharp', csharp);
hljs.registerLanguage('cs', csharp);
hljs.registerLanguage('php', php);
hljs.registerLanguage('ruby', ruby);
hljs.registerLanguage('rb', ruby);
hljs.registerLanguage('yaml', yaml);
hljs.registerLanguage('yml', yaml);

export interface CodeHighlightOptions {
  /** 是否启用自动检测语言 */
  autoDetect?: boolean;
}

export const codeHighlightPluginKey = new PluginKey('codeHighlight');

/**
 * 将 highlight.js 的 HTML 输出转换为 ProseMirror Decorations
 */
function getDecorations(doc: any, schema: Schema): DecorationSet {
  const decorations: Decoration[] = [];
  const codeBlockType = schema.nodes.codeBlock;

  if (!codeBlockType) {
    return DecorationSet.empty;
  }

  doc.descendants((node: any, pos: number) => {
    if (node.type !== codeBlockType) {
      return;
    }

    const code = node.textContent;
    const language = node.attrs.language || '';

    if (!code) {
      return;
    }

    try {
      let result;
      if (language && hljs.getLanguage(language)) {
        result = hljs.highlight(code, { language, ignoreIllegals: true });
      } else {
        // 尝试自动检测
        result = hljs.highlightAuto(code);
      }

      // 解析高亮结果并创建装饰
      const tokens = parseHighlightResult(result.value);
      let offset = pos + 1; // +1 跳过节点开始位置

      tokens.forEach((token) => {
        if (token.className) {
          decorations.push(
            Decoration.inline(offset, offset + token.text.length, {
              class: token.className,
            })
          );
        }
        offset += token.text.length;
      });
    } catch {
      // 高亮失败时忽略
    }
  });

  return DecorationSet.create(doc, decorations);
}

interface HighlightToken {
  text: string;
  className?: string;
}

/**
 * 解析 highlight.js 的 HTML 输出
 */
function parseHighlightResult(html: string): HighlightToken[] {
  const tokens: HighlightToken[] = [];
  const regex = /<span class="([^"]+)">([^<]*)<\/span>|([^<]+)/g;
  let match;

  while ((match = regex.exec(html)) !== null) {
    if (match[1] && match[2] !== undefined) {
      // <span class="...">text</span>
      tokens.push({
        text: decodeHtmlEntities(match[2]),
        className: `hljs-${match[1].replace('hljs-', '')}`,
      });
    } else if (match[3]) {
      // 纯文本
      tokens.push({
        text: decodeHtmlEntities(match[3]),
      });
    }
  }

  return tokens;
}

/**
 * 解码 HTML 实体
 */
function decodeHtmlEntities(str: string): string {
  return str
    .replace(/&lt;/g, '<')
    .replace(/&gt;/g, '>')
    .replace(/&amp;/g, '&')
    .replace(/&quot;/g, '"')
    .replace(/&#39;/g, "'")
    .replace(/&nbsp;/g, ' ');
}

export class CodeHighlight extends PluginExtension<CodeHighlightOptions> {
  get name(): string {
    return 'codeHighlight';
  }

  plugins(schema: Schema): Plugin[] {
    return [
      new Plugin({
        key: codeHighlightPluginKey,
        state: {
          init(_, { doc }) {
            return getDecorations(doc, schema);
          },
          apply(tr, decorationSet, oldState, newState) {
            // 只在文档变化时重新计算
            if (tr.docChanged) {
              return getDecorations(newState.doc, schema);
            }
            return decorationSet.map(tr.mapping, tr.doc);
          },
        },
        props: {
          decorations(state) {
            return this.getState(state);
          },
        },
      }),
    ];
  }
}

export default CodeHighlight;
