import { invoke } from '@tauri-apps/api/core';
import {
  ParseMarkdownRequest,
  ParseMarkdownResponse,
  QueryNodesRequest,
  QueryNodesResponse,
  FindNodeAtPositionRequest,
  FindNodeAtPositionResponse,
  ExtractOutlineRequest,
  ExtractOutlineResponse,
  ExtractLinksRequest,
  ExtractLinksResponse,
  ValidateMarkdownRequest,
  ValidateMarkdownResponse,
  MarkdownParseResult,
  MarkdownNode,
  OutlineItem,
  LinkInfo,
  ValidationResult,
  MarkdownParserConfig,
  QueryType,
} from '../types/markdown';

/**
 * Markdown解析服务类
 * 封装与Tauri后端的通信，提供易用的API接口
 */
export class MarkdownService {
  private static instance: MarkdownService;

  private constructor() {}

  /**
   * 获取单例实例
   */
  public static getInstance(): MarkdownService {
    if (!MarkdownService.instance) {
      MarkdownService.instance = new MarkdownService();
    }
    return MarkdownService.instance;
  }

  /**
   * 解析Markdown文档
   * @param text Markdown文本
   * @param config 解析器配置
   * @returns 解析结果
   */
  public async parseMarkdown(
    text: string,
    config?: MarkdownParserConfig
  ): Promise<MarkdownParseResult> {
    const request: ParseMarkdownRequest = {
      text,
      config,
    };

    const response = await invoke<ParseMarkdownResponse>('parse_markdown', {
      request,
    });

    if (!response.success || !response.result) {
      throw new Error(response.error || 'Failed to parse markdown');
    }

    return response.result;
  }

  /**
   * 查询特定类型的节点
   * @param text Markdown文本
   * @param queryType 查询类型
   * @returns 匹配的节点列表
   */
  public async queryNodes(
    text: string,
    queryType: QueryType | string
  ): Promise<MarkdownNode[]> {
    const request: QueryNodesRequest = {
      text,
      query_name: queryType,
    };

    const response = await invoke<QueryNodesResponse>('query_markdown_nodes', {
      request,
    });

    if (!response.success || !response.nodes) {
      throw new Error(response.error || 'Failed to query nodes');
    }

    return response.nodes;
  }

  /**
   * 根据位置查找节点
   * @param text Markdown文本
   * @param line 行号（从0开始）
   * @param column 列号（从0开始）
   * @returns 找到的节点，如果没有找到则返回null
   */
  public async findNodeAtPosition(
    text: string,
    line: number,
    column: number
  ): Promise<MarkdownNode | null> {
    const request: FindNodeAtPositionRequest = {
      text,
      line,
      column,
    };

    const response = await invoke<FindNodeAtPositionResponse>(
      'find_markdown_node_at_position',
      { request }
    );

    if (!response.success) {
      throw new Error(response.error || 'Failed to find node at position');
    }

    return response.node || null;
  }

  /**
   * 提取文档大纲
   * @param text Markdown文本
   * @returns 大纲项目列表
   */
  public async extractOutline(text: string): Promise<OutlineItem[]> {
    const request: ExtractOutlineRequest = {
      text,
    };

    const response = await invoke<ExtractOutlineResponse>(
      'extract_markdown_outline',
      { request }
    );

    if (!response.success || !response.outline) {
      throw new Error(response.error || 'Failed to extract outline');
    }

    return response.outline;
  }

  /**
   * 提取所有链接
   * @param text Markdown文本
   * @returns 链接信息列表
   */
  public async extractLinks(text: string): Promise<LinkInfo[]> {
    const request: ExtractLinksRequest = {
      text,
    };

    const response = await invoke<ExtractLinksResponse>(
      'extract_markdown_links',
      { request }
    );

    if (!response.success || !response.links) {
      throw new Error(response.error || 'Failed to extract links');
    }

    return response.links;
  }

  /**
   * 验证Markdown文档结构
   * @param text Markdown文本
   * @returns 验证结果
   */
  public async validateMarkdown(text: string): Promise<ValidationResult> {
    const request: ValidateMarkdownRequest = {
      text,
    };

    const response = await invoke<ValidateMarkdownResponse>(
      'validate_markdown',
      { request }
    );

    if (!response.success || !response.validation) {
      throw new Error(response.error || 'Failed to validate markdown');
    }

    return response.validation;
  }

  /**
   * 查询标题节点
   * @param text Markdown文本
   * @returns 标题节点列表
   */
  public async queryHeadings(text: string): Promise<MarkdownNode[]> {
    return this.queryNodes(text, QueryType.Headings);
  }

  /**
   * 查询链接节点
   * @param text Markdown文本
   * @returns 链接节点列表
   */
  public async queryLinkNodes(text: string): Promise<MarkdownNode[]> {
    return this.queryNodes(text, QueryType.Links);
  }

  /**
   * 查询代码块节点
   * @param text Markdown文本
   * @returns 代码块节点列表
   */
  public async queryCodeBlocks(text: string): Promise<MarkdownNode[]> {
    return this.queryNodes(text, QueryType.Code);
  }

  /**
   * 获取节点的纯文本内容
   * @param node Markdown节点
   * @returns 纯文本内容
   */
  public extractTextContent(node: MarkdownNode): string {
    if (node.node_type === 'Text') {
      return node.content;
    }

    return node.children
      .map((child) => this.extractTextContent(child))
      .join('');
  }

  /**
   * 检查节点是否在指定范围内
   * @param node Markdown节点
   * @param startLine 开始行号
   * @param endLine 结束行号
   * @returns 是否在范围内
   */
  public isNodeInRange(
    node: MarkdownNode,
    startLine: number,
    endLine: number
  ): boolean {
    return (
      node.range.start.line >= startLine && node.range.end.line <= endLine
    );
  }

  /**
   * 获取节点的行数
   * @param node Markdown节点
   * @returns 节点占用的行数
   */
  public getNodeLineCount(node: MarkdownNode): number {
    return node.range.end.line - node.range.start.line + 1;
  }

  /**
   * 查找包含指定文本的节点
   * @param nodes 节点列表
   * @param searchText 搜索文本
   * @returns 匹配的节点列表
   */
  public findNodesContainingText(
    nodes: MarkdownNode[],
    searchText: string
  ): MarkdownNode[] {
    const results: MarkdownNode[] = [];

    const searchInNode = (node: MarkdownNode) => {
      if (node.content.toLowerCase().includes(searchText.toLowerCase())) {
        results.push(node);
      }
      node.children.forEach(searchInNode);
    };

    nodes.forEach(searchInNode);
    return results;
  }

  /**
   * 获取节点的层级深度
   * @param node Markdown节点
   * @returns 层级深度
   */
  public getNodeDepth(node: MarkdownNode): number {
    let depth = 0;
    let current = node;

    while (current.children.length > 0) {
      depth++;
      current = current.children[0];
    }

    return depth;
  }

  /**
   * 将位置信息转换为字符串
   * @param line 行号
   * @param column 列号
   * @returns 位置字符串
   */
  public formatPosition(line: number, column: number): string {
    return `${line + 1}:${column + 1}`;
  }

  /**
   * 将范围信息转换为字符串
   * @param start 开始位置
   * @param end 结束位置
   * @returns 范围字符串
   */
  public formatRange(
    start: { line: number; column: number },
    end: { line: number; column: number }
  ): string {
    return `${this.formatPosition(start.line, start.column)}-${this.formatPosition(end.line, end.column)}`;
  }
}

/**
 * 导出单例实例
 */
export const markdownService = MarkdownService.getInstance();

/**
 * 默认导出
 */
export default markdownService;
