from app.modules.agent.engine.orchestrator.actions.explain_actions import ExplainActions
from app.modules.agent.engine.orchestrator.execution_context import ExecutionContext
from app.modules.agent.engine.orchestrator.models import (
    ExecutionPlan,
    OutputContract,
    RoutingMeta,
    Scenario,
    TaskConstraints,
    TaskSpec,
)


def _ctx(rag_items: list[dict]) -> ExecutionContext:
    task = TaskSpec(
        task_id="task-1",
        dialog_session_id="dialog-1",
        rag_session_id="rag-1",
        user_message="Объясни по коду как работает task_processor",
        scenario=Scenario.EXPLAIN_PART,
        routing=RoutingMeta(domain_id="project", process_id="qa", confidence=0.9, reason="test"),
        constraints=TaskConstraints(),
        output_contract=OutputContract(result_type="answer"),
        metadata={
            "rag_items": rag_items,
            "rag_context": "",
            "confluence_context": "",
            "files_map": {},
        },
    )
    plan = ExecutionPlan(
        plan_id="plan-1",
        task_id="task-1",
        scenario=Scenario.EXPLAIN_PART,
        template_id="tpl",
        template_version="1",
        steps=[],
    )
    return ExecutionContext(task=task, plan=plan, graph_resolver=lambda *_: None, graph_invoker=lambda *_: {})


def test_explain_actions_switch_to_code_profile_when_code_layers_present() -> None:
    ctx = _ctx(
        [
            {
                "source": "app/task_processor.py",
                "layer": "C1_SYMBOL_CATALOG",
                "title": "task_processor.process_task",
                "content": "function task_processor.process_task(task)",
                "metadata": {"qname": "task_processor.process_task", "kind": "function"},
            },
            {
                "source": "app/task_processor.py",
                "layer": "C2_DEPENDENCY_GRAPH",
                "title": "task_processor.process_task:calls",
                "content": "task_processor.process_task calls queue.publish",
                "metadata": {"edge_type": "calls"},
            },
        ]
    )
    actions = ExplainActions()

    actions.collect_sources(ctx)
    actions.extract_logic(ctx)
    actions.summarize(ctx)

    sources = ctx.artifacts.get_content("sources", {})
    assert sources["source_profile"] == "code"
    answer = str(ctx.artifacts.get_content("final_answer", ""))
    assert "кодовых слоев индекса" not in answer
    assert "CodeRAG" not in answer
    assert "app/task_processor.py" in answer
    assert "requirements/docs context" not in answer


def test_explain_actions_add_code_details_block() -> None:
    ctx = _ctx(
        [
            {
                "source": "src/config_manager/__init__.py",
                "layer": "C1_SYMBOL_CATALOG",
                "title": "ConfigManager",
                "content": "const ConfigManager\nConfigManager = config_manager.v2.ConfigManagerV2",
                "metadata": {
                    "qname": "ConfigManager",
                    "kind": "const",
                    "lang_payload": {"imported_from": "v2.ConfigManagerV2", "import_alias": True},
                },
            },
            {
                "source": "src/config_manager/v2/control/base.py",
                "layer": "C1_SYMBOL_CATALOG",
                "title": "ControlChannel",
                "content": "class ControlChannel\nControlChannel(ABC)",
                "metadata": {"qname": "ControlChannel", "kind": "class"},
            },
            {
                "source": "src/config_manager/v2/core/control_bridge.py",
                "layer": "C1_SYMBOL_CATALOG",
                "title": "ControlChannelBridge",
                "content": "class ControlChannelBridge\nПредоставляет halt и status как обработчики start/stop/status",
                "metadata": {"qname": "ControlChannelBridge", "kind": "class"},
            },
            {
                "source": "src/config_manager/v2/core/control_bridge.py",
                "layer": "C2_DEPENDENCY_GRAPH",
                "title": "ControlChannelBridge.on_start:calls",
                "content": "ControlChannelBridge.on_start calls self._start_runtime",
                "metadata": {"src_qname": "ControlChannelBridge.on_start", "dst_ref": "self._start_runtime"},
            },
            {
                "source": "src/config_manager/v2/__init__.py",
                "layer": "C0_SOURCE_CHUNKS",
                "title": "src/config_manager/v2/__init__.py:1-6",
                "content": '"""Контракт: управление через API (config.yaml, секция management)."""',
                "metadata": {},
            },
        ]
    )
    actions = ExplainActions()

    actions.collect_sources(ctx)
    actions.extract_logic(ctx)
    actions.summarize(ctx)

    answer = str(ctx.artifacts.get_content("final_answer", ""))
    assert "### Что видно по коду" in answer
    assert "ConfigManager` в проекте доступен как alias" in answer
    assert "ControlChannelBridge.on_start" in answer
    assert "### Где смотреть в проекте" in answer
    assert "В индексе нет точного символа" not in answer
    assert "отдельный интерфейс управления" in answer
