import { fromMarkdown } from "mdast-util-from-markdown";
import { toString } from "mdast-util-to-string";
import type { Heading, RootContent, Root } from "mdast";

export interface ParsedModuleCommand {
  module: string;
  command: string;
}

export interface ParsedResolverError {
  code: string;
  description: string;
}

export interface ParsedResolverDoc {
  resolverName: string;
  moduleCommands: ParsedModuleCommand[];
  errors: ParsedResolverError[];
}

const MODULE_COMMAND_PATTERN = /([a-z][\w-]*)\.(\w+)/;
const TABLE_ROW_PATTERN = /^\|(.+)\|(.+)\|$/;

export function parseResolverDoc(fileName: string, markdown: string): ParsedResolverDoc {
  const resolverName = fileName.charAt(0).toLowerCase() + fileName.slice(1);
  const tree = fromMarkdown(markdown);

  return {
    resolverName,
    moduleCommands: parseModuleCommands(tree),
    errors: parseExceptionHandlingFromRaw(markdown),
  };
}

function isHeading(node: RootContent): node is Heading {
  return node.type === "heading";
}

function getNodesUnderHeading(tree: Root, headingText: string): RootContent[] {
  const nodes: RootContent[] = [];
  let collecting = false;

  for (const node of tree.children) {
    if (isHeading(node)) {
      if (collecting) break;
      if (node.depth === 2 && toString(node) === headingText) {
        collecting = true;
        continue;
      }
    }
    if (collecting) {
      nodes.push(node);
    }
  }

  return nodes;
}

function parseModuleCommands(tree: Root): ParsedModuleCommand[] {
  const nodes = getNodesUnderHeading(tree, "Modules Commands Used");
  const commands: ParsedModuleCommand[] = [];

  for (const node of nodes) {
    if (node.type !== "list") continue;

    for (const item of node.children) {
      const text = toString(item);
      const match = MODULE_COMMAND_PATTERN.exec(text);
      if (match) {
        commands.push({ module: match[1], command: match[2] });
      }
    }
  }

  return commands;
}

function parseExceptionHandlingFromRaw(markdown: string): ParsedResolverError[] {
  const lines = markdown.split("\n");
  const errors: ParsedResolverError[] = [];

  // Find the "## Exception Handling" heading
  let inSection = false;
  let headerSkipped = false;
  let separatorSkipped = false;

  for (const line of lines) {
    const trimmed = line.trim();

    if (trimmed.startsWith("## Exception Handling")) {
      inSection = true;
      continue;
    }

    if (!inSection) continue;

    // Stop at next heading
    if (trimmed.startsWith("#")) break;

    // Skip empty lines
    if (!trimmed) continue;

    // Parse table rows
    const match = TABLE_ROW_PATTERN.exec(trimmed);
    if (!match) continue;

    // Skip header row and separator row
    if (!headerSkipped) {
      headerSkipped = true;
      continue;
    }
    if (!separatorSkipped) {
      separatorSkipped = true;
      continue;
    }

    const code = match[1].trim();
    const description = match[2].trim();
    if (code) {
      errors.push({ code, description });
    }
  }

  return errors;
}
