/**
 * Tag 提取器
 * 使用 Tree-sitter 解析代码并提取符号定义和引用
 */

import * as fs from 'fs/promises';
import * as path from 'path';
import { fileURLToPath } from 'url';
import type { Tag } from '../types.js';
import { getLanguageFromFilename } from '../types.js';

// Tree-sitter 类型（web-tree-sitter）
interface TreeSitterParser {
  parse(input: string): TreeSitterTree;
  setLanguage(language: TreeSitterLanguage): void;
  getLanguage(): TreeSitterLanguage;
}

interface TreeSitterTree {
  rootNode: TreeSitterNode;
}

interface TreeSitterNode {
  text: string;
  startPosition: { row: number; column: number };
  endPosition: { row: number; column: number };
  type: string;
  childCount: number;
  namedChildCount: number;
  children: TreeSitterNode[];
  namedChildren: TreeSitterNode[];
}

interface TreeSitterLanguage {
  query(source: string): TreeSitterQuery;
}

interface TreeSitterQuery {
  captures(node: TreeSitterNode): TreeSitterCapture[];
}

interface TreeSitterCapture {
  node: TreeSitterNode;
  name: string;
}

// 动态导入 web-tree-sitter
let ParserClass: any = null;
let treeSitterInitialized = false;

/**
 * 初始化 Tree-sitter
 */
async function initTreeSitter(): Promise<void> {
  if (treeSitterInitialized) return;

  try {
    const TreeSitter = await import('web-tree-sitter');
    // Parser 是命名导出的类，init 是其静态方法
    await TreeSitter.Parser.init();
    ParserClass = TreeSitter.Parser;
    treeSitterInitialized = true;
  } catch (error) {
    console.warn('Failed to initialize tree-sitter:', error);
    throw new Error('Tree-sitter initialization failed');
  }
}

/**
 * Tag 提取器类
 */
export class TagExtractor {
  private parsers: Map<string, TreeSitterParser> = new Map();
  private languages: Map<string, TreeSitterLanguage> = new Map();
  private queries: Map<string, TreeSitterQuery> = new Map();
  private initialized = false;
  private queriesDir: string;

  constructor() {
    // 获取查询文件目录
    const __filename = fileURLToPath(import.meta.url);
    const __dirname = path.dirname(__filename);
    this.queriesDir = path.join(__dirname, 'queries');
  }

  /**
   * 初始化提取器
   */
  async initialize(): Promise<void> {
    if (this.initialized) return;

    try {
      await initTreeSitter();
      this.initialized = true;
    } catch (error) {
      // Tree-sitter 初始化失败，使用回退方案
      console.warn('Tree-sitter not available, using regex fallback');
      this.initialized = true;
    }
  }

  /**
   * 获取文件的所有 tags
   */
  async getTags(fname: string, relFname: string): Promise<Tag[]> {
    await this.initialize();

    const lang = getLanguageFromFilename(fname);
    if (!lang) return [];

    let code: string;
    try {
      code = await fs.readFile(fname, 'utf-8');
    } catch {
      return [];
    }

    // 尝试使用 Tree-sitter
    if (ParserClass) {
      try {
        const tags = await this.extractWithTreeSitter(code, fname, relFname, lang);
        if (tags.length > 0) {
          return tags;
        }
      } catch (error) {
        // Tree-sitter 解析失败，回退到正则
      }
    }

    // 回退到正则表达式
    return this.extractWithRegex(code, fname, relFname, lang);
  }

  /**
   * 使用 Tree-sitter 提取 tags
   */
  private async extractWithTreeSitter(
    code: string,
    fname: string,
    relFname: string,
    lang: string
  ): Promise<Tag[]> {
    const parser = await this.getParser(lang);
    const query = await this.getQuery(lang);

    if (!parser || !query) {
      return [];
    }

    const tree = parser.parse(code);
    const captures = query.captures(tree.rootNode);

    const tags: Tag[] = [];
    const seenKinds = new Set<string>();

    for (const capture of captures) {
      const { node, name } = capture;

      let kind: 'def' | 'ref' | null = null;
      if (name.startsWith('name.definition.')) {
        kind = 'def';
      } else if (name.startsWith('name.reference.')) {
        kind = 'ref';
      } else {
        continue;
      }

      seenKinds.add(kind);

      tags.push({
        relFname,
        fname,
        name: node.text,
        kind,
        line: node.startPosition.row,
      });
    }

    // 如果只有 def 没有 ref，使用正则回退提取引用
    if (seenKinds.has('def') && !seenKinds.has('ref')) {
      const refTags = this.extractRefsWithRegex(code, fname, relFname);
      tags.push(...refTags);
    }

    return tags;
  }

  /**
   * 获取或创建解析器
   */
  private async getParser(lang: string): Promise<TreeSitterParser | null> {
    if (this.parsers.has(lang)) {
      return this.parsers.get(lang)!;
    }

    try {
      const language = await this.getLanguage(lang);
      if (!language) return null;

      const parser = new ParserClass();
      parser.setLanguage(language);
      this.parsers.set(lang, parser);
      return parser;
    } catch {
      return null;
    }
  }

  /**
   * 获取语言定义
   */
  private async getLanguage(lang: string): Promise<TreeSitterLanguage | null> {
    if (this.languages.has(lang)) {
      return this.languages.get(lang)!;
    }

    try {
      // 尝试加载 WASM 语言文件
      const wasmPath = this.getWasmPath(lang);
      const language = await ParserClass.Language.load(wasmPath);
      this.languages.set(lang, language);
      return language;
    } catch {
      return null;
    }
  }

  /**
   * 获取 WASM 文件路径
   */
  private getWasmPath(lang: string): string {
    // tree-sitter WASM 文件的标准位置
    const wasmName = `tree-sitter-${lang}.wasm`;

    // 尝试多个可能的位置
    const possiblePaths = [
      path.join(process.cwd(), 'node_modules', 'tree-sitter-wasms', 'out', wasmName),
      path.join(process.cwd(), 'node_modules', `tree-sitter-${lang}`, wasmName),
      path.join(__dirname, '..', '..', '..', 'wasm', wasmName),
    ];

    // 返回第一个路径（实际使用时需要检查存在性）
    return possiblePaths[0];
  }

  /**
   * 获取语言查询
   */
  private async getQuery(lang: string): Promise<TreeSitterQuery | null> {
    if (this.queries.has(lang)) {
      return this.queries.get(lang)!;
    }

    try {
      const language = await this.getLanguage(lang);
      if (!language) return null;

      const queryPath = path.join(this.queriesDir, `${lang}-tags.scm`);
      const queryText = await fs.readFile(queryPath, 'utf-8');
      const query = language.query(queryText);
      this.queries.set(lang, query);
      return query;
    } catch {
      return null;
    }
  }

  /**
   * 使用正则表达式提取 tags (回退方案)
   */
  private extractWithRegex(
    code: string,
    fname: string,
    relFname: string,
    lang: string
  ): Tag[] {
    const tags: Tag[] = [];
    const lines = code.split('\n');

    // 根据语言选择正则模式
    const patterns = this.getRegexPatterns(lang);

    lines.forEach((line, lineNum) => {
      for (const pattern of patterns.definitions) {
        const match = line.match(pattern.regex);
        if (match && match[pattern.nameGroup]) {
          tags.push({
            relFname,
            fname,
            name: match[pattern.nameGroup],
            kind: 'def',
            line: lineNum,
          });
        }
      }
    });

    // 提取引用
    tags.push(...this.extractRefsWithRegex(code, fname, relFname));

    return tags;
  }

  /**
   * 使用正则提取引用
   */
  private extractRefsWithRegex(code: string, fname: string, relFname: string): Tag[] {
    const tags: Tag[] = [];

    // 简单的标识符匹配 - 排除关键字
    const keywords = new Set([
      'if',
      'else',
      'for',
      'while',
      'do',
      'switch',
      'case',
      'break',
      'continue',
      'return',
      'function',
      'class',
      'const',
      'let',
      'var',
      'import',
      'export',
      'from',
      'default',
      'async',
      'await',
      'try',
      'catch',
      'finally',
      'throw',
      'new',
      'this',
      'super',
      'extends',
      'implements',
      'interface',
      'type',
      'enum',
      'public',
      'private',
      'protected',
      'static',
      'readonly',
      'abstract',
      'true',
      'false',
      'null',
      'undefined',
      'void',
      'never',
      'any',
      'unknown',
      'string',
      'number',
      'boolean',
      'object',
      'symbol',
      'bigint',
      'def',
      'class',
      'self',
      'None',
      'True',
      'False',
      'and',
      'or',
      'not',
      'in',
      'is',
      'lambda',
      'with',
      'as',
      'pass',
      'raise',
      'yield',
      'global',
      'nonlocal',
      'assert',
      'del',
    ]);

    // 匹配 PascalCase 或 snake_case 标识符（更可能是用户定义的）
    const identRegex = /\b([A-Z][a-zA-Z0-9]*|[a-z][a-zA-Z0-9]*_[a-zA-Z0-9_]*)\b/g;
    let match;

    while ((match = identRegex.exec(code)) !== null) {
      const name = match[1];
      if (!keywords.has(name) && name.length >= 2) {
        tags.push({
          relFname,
          fname,
          name,
          kind: 'ref',
          line: -1, // 行号未知
        });
      }
    }

    return tags;
  }

  /**
   * 获取语言的正则模式
   */
  private getRegexPatterns(lang: string): {
    definitions: Array<{ regex: RegExp; nameGroup: number }>;
  } {
    switch (lang) {
      case 'typescript':
      case 'javascript':
        return {
          definitions: [
            // function name(
            { regex: /(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*[<(]/, nameGroup: 1 },
            // class Name
            { regex: /(?:export\s+)?(?:abstract\s+)?class\s+(\w+)/, nameGroup: 1 },
            // interface Name
            { regex: /(?:export\s+)?interface\s+(\w+)/, nameGroup: 1 },
            // type Name =
            { regex: /(?:export\s+)?type\s+(\w+)\s*[<=]/, nameGroup: 1 },
            // const/let/var name = (arrow function or function)
            {
              regex: /(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:\([^)]*\)|[^=])\s*=>/,
              nameGroup: 1,
            },
            // enum Name
            { regex: /(?:export\s+)?enum\s+(\w+)/, nameGroup: 1 },
            // method name(
            { regex: /^\s*(?:async\s+)?(\w+)\s*\([^)]*\)\s*[:{]/, nameGroup: 1 },
          ],
        };

      case 'python':
        return {
          definitions: [
            // def name(
            { regex: /^\s*(?:async\s+)?def\s+(\w+)\s*\(/, nameGroup: 1 },
            // class Name
            { regex: /^\s*class\s+(\w+)/, nameGroup: 1 },
          ],
        };

      default:
        return {
          definitions: [
            // 通用：function/def/class 后面的标识符
            { regex: /(?:function|def|class)\s+(\w+)/, nameGroup: 1 },
          ],
        };
    }
  }
}

/**
 * 创建 Tag 提取器实例
 */
export function createTagExtractor(): TagExtractor {
  return new TagExtractor();
}
