"""Behave steps for project_context_phase_analysis.feature."""

from __future__ import annotations

from typing import Any

from behave import given, then, when

from cleveragents.application.services.context_phase_analysis import (
    analyze_phase_summaries,
)
from cleveragents.domain.models.acms.tiers import ContextTier, TieredFragment
from cleveragents.domain.models.core.context_policy import (
    ContextView,
    ProjectContextPolicy,
)


def _base_policy() -> ProjectContextPolicy:
    return ProjectContextPolicy(
        default_view=ContextView(
            include_resources=["local/*"],
            max_file_size=2_000_000,
            max_total_size=5_000_000,
        ),
        strategize_view=ContextView(
            include_resources=["local/*"],
            include_paths=["src/**/*.py", "docs/**/*.md"],
            exclude_paths=["**/test_*.py"],
            max_file_size=1_000_000,
            max_total_size=2_000_000,
        ),
        execute_view=ContextView(
            include_resources=["local/*"],
            include_paths=["src/**/*.py"],
            exclude_paths=["**/test_*.py", "**/conftest.py"],
            max_file_size=500_000,
            max_total_size=700_000,
        ),
        apply_view=ContextView(
            include_resources=["local/*"],
            include_paths=["src/**/*.py"],
            exclude_paths=["docs/**"],
            max_file_size=250_000,
            max_total_size=400_000,
        ),
    )


@given("a phase analysis policy with narrowing limits")
def step_policy(context: Any) -> None:
    context.phase_policy = _base_policy()


@given("no tiered fragments for phase analysis")
def step_no_fragments(context: Any) -> None:
    context.phase_fragments = []


@given("a single resource fragment for phase analysis")
def step_single_fragment(context: Any) -> None:
    context.phase_fragments = [
        TieredFragment(
            fragment_id="single",
            content="x" * 100,
            tier=ContextTier.HOT,
            resource_id="local/repo-a",
            project_name="local/ctx-app",
            token_count=120,
            metadata={"path": "src/main.py", "byte_size": 100_000},
        )
    ]


@given("multiple resource fragments for phase analysis")
def step_multiple_resources(context: Any) -> None:
    context.phase_fragments = [
        TieredFragment(
            fragment_id="a",
            content="x" * 80,
            tier=ContextTier.HOT,
            resource_id="local/repo-a",
            project_name="local/ctx-app",
            token_count=100,
            metadata={"path": "src/a.py", "byte_size": 80_000},
        ),
        TieredFragment(
            fragment_id="b",
            content="x" * 90,
            tier=ContextTier.WARM,
            resource_id="local/repo-b",
            project_name="local/ctx-app",
            token_count=110,
            metadata={"path": "src/b.py", "byte_size": 90_000},
        ),
    ]


@given("budget constrained fragments for phase analysis")
def step_budget_fragments(context: Any) -> None:
    context.phase_fragments = [
        TieredFragment(
            fragment_id="f1",
            content="x" * 400,
            tier=ContextTier.HOT,
            resource_id="local/repo-a",
            project_name="local/ctx-app",
            token_count=450,
            metadata={"path": "src/core.py", "byte_size": 400_000},
        ),
        TieredFragment(
            fragment_id="f2",
            content="x" * 380,
            tier=ContextTier.WARM,
            resource_id="local/repo-a",
            project_name="local/ctx-app",
            token_count=430,
            metadata={"path": "src/engine.py", "byte_size": 380_000},
        ),
        TieredFragment(
            fragment_id="f3",
            content="x" * 200,
            tier=ContextTier.COLD,
            resource_id="local/repo-a",
            project_name="local/ctx-app",
            token_count=220,
            metadata={"path": "docs/design.md", "byte_size": 200_000},
        ),
    ]


@when("I compute project context phase analysis with budget {budget:d}")
def step_compute(context: Any, budget: int) -> None:
    context.phase_result = analyze_phase_summaries(
        context.phase_policy,
        context.phase_fragments,
        budget,
    )


@then("each phase summary should include resource and size metrics")
def step_metrics_present(context: Any) -> None:
    for phase in ("strategize", "execute", "apply"):
        row = context.phase_result["phases"][phase]
        assert "resource_count" in row
        assert "total_bytes" in row
        assert "budget_used_ratio" in row


@then("phase analysis should report monotonic narrowing")
def step_narrowing(context: Any) -> None:
    narrowing = context.phase_result["narrowing"]
    assert narrowing["overall"] is True


@then("each phase summary should include human-readable text")
def step_summary_text(context: Any) -> None:
    for phase in ("strategize", "execute", "apply"):
        summary = context.phase_result["phases"][phase]["summary"]
        assert isinstance(summary, str)
        assert phase in summary


@then("strategize phase should include at least one fragment")
def step_strat_non_empty(context: Any) -> None:
    assert context.phase_result["phases"]["strategize"]["fragment_count"] >= 1


@then("strategize phase resource count should be 2")
def step_resource_count_two(context: Any) -> None:
    assert context.phase_result["phases"]["strategize"]["resource_count"] == 2


@then("execute phase should have fewer tokens than strategize phase")
def step_execute_less(context: Any) -> None:
    strat_tokens = context.phase_result["phases"]["strategize"]["total_tokens"]
    exec_tokens = context.phase_result["phases"]["execute"]["total_tokens"]
    assert exec_tokens < strat_tokens


@then("apply phase should have fewer or equal tokens than execute phase")
def step_apply_less_or_equal(context: Any) -> None:
    exec_tokens = context.phase_result["phases"]["execute"]["total_tokens"]
    apply_tokens = context.phase_result["phases"]["apply"]["total_tokens"]
    assert apply_tokens <= exec_tokens
