from __future__ import annotations

import re

import yaml

from app.core.agent.processes.v2.workflows.doc_update_from_feature_v2.subprocesses.common.template_models import (
    TemplateSection,
    TemplateSpec,
)


class TemplateParser:
    _HEADING_RE = re.compile(r"^(#{1,6})\s+(.+?)\s*$")
    _RULE_REF_RE = re.compile(r"`(\.\./common-elements/[^`]+|common-elements/[^`]+)`")

    def parse(self, source_name: str, template_text: str) -> TemplateSpec:
        _, body = self._split_frontmatter(template_text)
        doc_type = self._doc_type(template_text, source_name)
        title_level = 1
        sections: list[TemplateSection] = []
        lines = body.splitlines()
        index = 0
        while index < len(lines):
            heading = self._match_heading(lines[index])
            if not heading:
                index += 1
                continue
            level, title = heading
            if "<title>" in title:
                title_level = level
                index += 1
                continue
            rule_path = self._extract_rule_path(lines, index + 1)
            sections.append(TemplateSection(title=title, level=level, rule_path=rule_path))
            index += 1
        self._mark_children(sections)
        return TemplateSpec(
            doc_type=doc_type,
            source_name=source_name,
            template_text=template_text,
            title_level=title_level,
            sections=sections,
        )

    def _split_frontmatter(self, text: str) -> tuple[dict[str, object], str]:
        value = text.strip()
        if not value.startswith("---\n"):
            return {}, text
        _, _, tail = value.partition("---\n")
        frontmatter_text, _, body = tail.partition("\n---\n")
        payload = yaml.safe_load(frontmatter_text) or {}
        return payload if isinstance(payload, dict) else {}, body

    def _doc_type(self, text: str, source_name: str) -> str:
        frontmatter, _ = self._split_frontmatter(text)
        doc_type = str(frontmatter.get("doc_type") or "").strip()
        if doc_type:
            return doc_type
        suffix = ".template.md"
        filename = source_name.split("/")[-1]
        return filename[: -len(suffix)] if filename.endswith(suffix) else filename

    def _match_heading(self, line: str) -> tuple[int, str] | None:
        match = self._HEADING_RE.match(line.strip())
        if not match:
            return None
        return len(match.group(1)), match.group(2).strip()

    def _extract_rule_path(self, lines: list[str], start: int) -> str:
        limit = min(len(lines), start + 4)
        for index in range(start, limit):
            match = self._RULE_REF_RE.search(lines[index])
            if not match:
                continue
            return match.group(1).replace("../", "")
        return ""

    def _mark_children(self, sections: list[TemplateSection]) -> None:
        for index, section in enumerate(sections):
            if index + 1 >= len(sections):
                continue
            section.has_children = sections[index + 1].level > section.level
