from __future__ import annotations

from types import SimpleNamespace

from app.core.agent.processes.v2.workflows.doc_update_from_feature_v2.steps.step3_parse_requirements.parser import (
    FunctionalRequirementsParser,
)
from app.core.agent.processes.v2.workflows.doc_update_from_feature_v2.steps.step4_prepare_tasks.services import (
    RequirementTaskBuilder,
    RequirementTaskOrderer,
)
from app.core.agent.processes.v2.workflows.doc_update_from_feature_v2.steps.step5_execute_subprocesses.classifier import (
    DeleteIntentHeuristic,
)
from app.core.agent.processes.v2.workflows.doc_update_from_feature_v2.subprocesses.common.source_sections import (
    RequirementSourceSections,
)
from app.core.agent.processes.v2.workflows.doc_update_from_feature_v2.subprocesses.common.template_parser import (
    TemplateParser,
)
from app.core.agent.processes.v2.workflows.doc_update_from_feature_v2.workflow_runtime.context import (
    DocUpdateFromFeatureV2Context,
)
from app.core.agent.processes.v2.workflows.doc_update_from_feature_v2.workflow_runtime.models import (
    AnalyticsMeta,
    RequirementUnit,
)


class _UnexpectedLlmCall:
    def generate(self, *args, **kwargs):  # noqa: ANN002, ANN003
        raise AssertionError("LLM should not be called for explicit happy-path metadata.")


def test_parser_reads_section_6_metadata_and_units() -> None:
    parser = FunctionalRequirementsParser()
    content = """
analysis_id: AN-42
application: loyalty
platform: web

# 6. Функциональные требования
domain: billing
sub_domain: payments

## 6.1 Экран статуса платежа
id: payment-status
doc_type: ui_page
application: loyalty
platform: pprb

### Функциональные требования
- Показываем статус и ошибку.

## 6.2 Метод получения статуса
id: get-payment-status
doc_type: api_method
application: loyalty
platform: ufs

### Контракт метода
- GET /payments/status
""".strip()

    meta, units = parser.parse(content)

    assert meta.analysis_id == "AN-42"
    assert meta.application == "loyalty"
    assert meta.platform == "web"
    assert meta.domain == "billing"
    assert meta.subdomain == "payments"
    assert [unit.section_key for unit in units] == ["6.1", "6.2"]
    assert [unit.heading for unit in units] == ["Экран статуса платежа", "Метод получения статуса"]
    assert units[0].metadata["doc_type"] == "ui_page"
    assert "Показываем статус" in units[0].body


def test_parser_reads_backticked_root_metadata_format() -> None:
    parser = FunctionalRequirementsParser()
    content = """
# 6. Описание изменений

- `domain`: `orders`
- `sub_domain`: `list_read`

## 6.1 Страница списка заказов
id: orders.ui.list
doc_type: ui_page
application: orders_web
platform: web

### Требования к UI
- Таблица заказов.
""".strip()

    meta, units = parser.parse(content)

    assert meta.domain == "orders"
    assert meta.subdomain == "list_read"
    assert len(units) == 1
    assert units[0].metadata["doc_type"] == "ui_page"


def test_task_builder_orders_platforms_and_inherits_root_context() -> None:
    context = DocUpdateFromFeatureV2Context(
        runtime=SimpleNamespace(),
        route=SimpleNamespace(),
        rag_session_id="",
        analytics_meta=AnalyticsMeta(
            analysis_id="AN-42",
            application="loyalty",
            domain="billing",
            subdomain="payments",
        ),
        requirements=[
            RequirementUnit(
                section_key="6.3",
                heading="WEB страница",
                body="Описание",
                metadata={"id": "web-page", "doc_type": "ui_page", "platform": "web", "op": "create"},
            ),
            RequirementUnit(
                section_key="6.1",
                heading="PPRB страница",
                body="Описание",
                metadata={"id": "pprb-page", "doc_type": "ui_page", "platform": "pprb", "op": "create"},
            ),
            RequirementUnit(
                section_key="6.2",
                heading="UFS метод",
                body="Описание",
                metadata={"id": "ufs-method", "doc_type": "api_method", "platform": "ufs", "op": "create"},
            ),
        ],
    )
    builder = RequirementTaskBuilder(_UnexpectedLlmCall())
    orderer = RequirementTaskOrderer()

    tasks = orderer.order(builder.build(context))

    assert [task.platform for task in tasks] == ["pprb", "ufs", "web"]
    assert [task.section_key for task in tasks] == ["6.1", "6.2", "6.3"]
    assert all(task.application == "loyalty" for task in tasks)
    assert all(task.domain == "billing" for task in tasks)
    assert all(task.subdomain == "payments" for task in tasks)
    assert tasks[0].path == "docs/billing/pprb/ui_page/pprb-page.md"


def test_task_builder_uses_create_when_path_is_new_and_no_delete_markers() -> None:
    context = DocUpdateFromFeatureV2Context(
        runtime=SimpleNamespace(),
        route=SimpleNamespace(),
        rag_session_id="",
        analytics_meta=AnalyticsMeta(
            application="orders_web",
            domain="orders",
            subdomain="list_read",
        ),
        requirements=[
            RequirementUnit(
                section_key="6.1",
                heading="Страница списка заказов",
                body="### Требования к UI\n- Показывать таблицу заказов.",
                metadata={
                    "id": "orders.ui.list",
                    "doc_type": "ui_page",
                    "application": "orders_web",
                    "platform": "web",
                },
            )
        ],
    )

    tasks = RequirementTaskBuilder(_UnexpectedLlmCall()).build(context)

    assert len(tasks) == 1
    assert tasks[0].action.value == "create"
    assert tasks[0].path == "docs/orders/web/ui_page/orders.ui.list.md"


def test_delete_heuristic_does_not_match_phrase_ne_udalos() -> None:
    heuristic = DeleteIntentHeuristic()

    assert heuristic.is_delete("Не удалось загрузить список заказов.") is False
    assert heuristic.is_delete("Нужно удалить существующую страницу документации.") is True


def test_template_parser_extracts_ordered_sections_from_ui_template() -> None:
    parser = TemplateParser()
    template = """
---
doc_type: ui_page
---

# <title>

## Summary
Правила оформления: `../common-elements/summary.md`

## Details
Правила оформления: `../common-elements/details.md`

### Требования к UI
Правила оформления: `../common-elements/ui-requirements.md`
""".strip()

    spec = parser.parse("templates/ui_page.template.md", template)

    assert spec.doc_type == "ui_page"
    assert spec.title_level == 1
    assert [(item.level, item.title, item.rule_path) for item in spec.sections] == [
        (2, "Summary", "common-elements/summary.md"),
        (2, "Details", "common-elements/details.md"),
        (3, "Требования к UI", "common-elements/ui-requirements.md"),
    ]
    assert spec.sections[1].has_children is True


def test_requirement_source_sections_match_template_titles() -> None:
    locator = RequirementSourceSections()
    body = """
### Технический use case (тезисно)
1. Открыть экран.

### Контракт метода
| Поле | Тип |

### Нефункциональные требования
- Метрики.
""".strip()

    sections = locator.extract(body)

    assert "открыть экран" not in sections
    assert locator.find_for_title(sections, "Технический use case") == "1. Открыть экран."
    assert "| Поле | Тип |" in locator.find_for_title(sections, "Контракт")
