from __future__ import annotations

from dataclasses import dataclass

from app.core.agent.processes.v2.workflows.doc_update_from_feature.workflow_runtime.models import (
    AnalyticsMeta,
    FeatureRequirementUnit,
)


@dataclass(slots=True)
class ParsedFeatureSpec:
    meta: AnalyticsMeta
    units: list[FeatureRequirementUnit]


class FeatureMarkdownParser:
    _META_KEYS = {"analysis_id", "application", "platform", "domain", "sub_domain", "domains", "subdomains"}

    def parse(self, content: str) -> ParsedFeatureSpec:
        lines = content.splitlines()
        meta = self._parse_meta(lines)
        section_lines = self._extract_functional_section(lines)
        units = self._parse_units(section_lines)
        return ParsedFeatureSpec(meta=meta, units=units)

    def _parse_meta(self, lines: list[str]) -> AnalyticsMeta:
        values: dict[str, object] = {}
        i = 0
        while i < len(lines):
            line = lines[i].strip()
            if line.startswith("## "):
                break
            if ":" not in line:
                i += 1
                continue
            key, raw = [part.strip() for part in line.split(":", 1)]
            if key not in self._META_KEYS:
                i += 1
                continue
            if raw:
                values[key] = raw.strip("\"'")
                i += 1
                continue
            items: list[str] = []
            j = i + 1
            while j < len(lines):
                item_line = lines[j]
                if not item_line.startswith("  - ") and not item_line.startswith("- "):
                    break
                items.append(item_line.split("-", 1)[1].strip().strip("\"'"))
                j += 1
            values[key] = items
            i = j
        return AnalyticsMeta(
            analysis_id=str(values.get("analysis_id") or "").strip(),
            application=str(values.get("application") or "").strip(),
            platform=str(values.get("platform") or "").strip(),
            domains=self._as_list(values.get("domain") or values.get("domains")),
            subdomains=self._as_list(values.get("sub_domain") or values.get("subdomains")),
        )

    def _extract_functional_section(self, lines: list[str]) -> list[str]:
        started = False
        section: list[str] = []
        for line in lines:
            stripped = line.strip()
            if stripped.startswith("## "):
                if self._is_functional_heading(stripped):
                    started = True
                    continue
                if started:
                    break
            if started:
                section.append(line)
        return section

    def _is_functional_heading(self, value: str) -> bool:
        lowered = value.lower()
        return "функциональные требования" in lowered and lowered.startswith("## 5")

    def _parse_units(self, section_lines: list[str]) -> list[FeatureRequirementUnit]:
        units: list[FeatureRequirementUnit] = []
        current_title = ""
        current_lines: list[str] = []
        for line in section_lines:
            if line.strip().startswith("### "):
                if current_title:
                    units.append(self._build_unit(current_title, current_lines))
                current_title = line.strip()[4:].strip()
                current_lines = []
                continue
            if current_title:
                current_lines.append(line)
        if current_title:
            units.append(self._build_unit(current_title, current_lines))
        return units

    def _build_unit(self, title: str, lines: list[str]) -> FeatureRequirementUnit:
        metadata, body = self._split_metadata_and_body(lines)
        return FeatureRequirementUnit(heading=title, body="\n".join(body).strip(), metadata=metadata)

    def _split_metadata_and_body(self, lines: list[str]) -> tuple[dict[str, object], list[str]]:
        meta: dict[str, object] = {}
        body_start = 0
        i = 0
        while i < len(lines):
            raw = lines[i]
            stripped = raw.strip()
            if not stripped:
                body_start = i + 1
                i += 1
                continue
            line = stripped[2:].strip() if stripped.startswith("- ") else stripped
            if ":" not in line:
                break
            key, value = [part.strip() for part in line.split(":", 1)]
            if not key.isidentifier():
                break
            if value:
                meta[key] = value.strip("\"'")
                body_start = i + 1
                i += 1
                continue
            items: list[str] = []
            j = i + 1
            while j < len(lines) and lines[j].lstrip().startswith("- "):
                items.append(lines[j].split("-", 1)[1].strip().strip("\"'"))
                j += 1
            meta[key] = items
            body_start = j
            i = j
        return meta, lines[body_start:]

    def _as_list(self, value: object) -> list[str]:
        if isinstance(value, list):
            return [str(item).strip() for item in value if str(item).strip()]
        if isinstance(value, str) and value.strip():
            return [value.strip()]
        return []
