# pyright: reportRedeclaration=false
"""Step definitions for skill CLI uncovered-lines coverage."""

from __future__ import annotations

from unittest.mock import patch

from behave import given, then, when
from typer.testing import CliRunner

from cleveragents.cli.commands.skill import (
    _get_skill_service,
    _reset_skill_service,
)
from cleveragents.cli.commands.skill import (
    app as skill_app,
)
from cleveragents.domain.models.core.skill import (
    Skill,
    SkillAgentSource,
    SkillInclude,
    SkillMcpSource,
)

# ── helpers ─────────────────────────────────────────────────


def _make_skill(
    name: str,
    description: str = "test skill",
    tool_refs: list[str] | None = None,
    includes: list[SkillInclude] | None = None,
    mcp_servers: list[SkillMcpSource] | None = None,
    agent_skills: list[SkillAgentSource] | None = None,
) -> Skill:
    return Skill(
        name=name,
        description=description,
        tool_refs=tool_refs or [],
        includes=includes or [],
        mcp_servers=mcp_servers or [],
        agent_skills=agent_skills or [],
    )


# ── Given ───────────────────────────────────────────────────


@given("a clean skill service")
def step_clean_skill_service(context):
    _reset_skill_service()
    context.runner = CliRunner()
    context.service = _get_skill_service()


@given("a skill with an include pointing to a non-registered skill")
def step_skill_with_unregistered_include(context):
    skill = _make_skill(
        name="local/inc-parent",
        includes=[SkillInclude(name="local/missing-child")],
    )
    context.service._skills[skill.name] = skill
    context.skill_name = skill.name


@given("a registered skill for capability error testing")
def step_skill_for_capability_error(context):
    skill = _make_skill(
        name="local/cap-error",
        tool_refs=["builtin/read-file"],
    )
    context.service._skills[skill.name] = skill
    context.skill_name = skill.name


@given("a registered skill for dependent actors testing")
def step_skill_for_dependent_actors(context):
    skill = _make_skill(
        name="local/dep-actors",
        tool_refs=["builtin/write-file"],
    )
    context.service._skills[skill.name] = skill
    context.skill_name = skill.name


@given("a registered skill with agent_skill sources")
def step_skill_with_agent_skills(context):
    skill = _make_skill(
        name="local/with-agents",
        agent_skills=[SkillAgentSource(path="./skills/my-agent")],
    )
    context.service._skills[skill.name] = skill
    context.skill_name = skill.name


@given("a registered skill for removal with actor dependents")
def step_skill_for_removal_actors(context):
    skill = _make_skill(
        name="local/removable-actors",
        tool_refs=["builtin/exec"],
    )
    context.service._skills[skill.name] = skill
    context.skill_name = skill.name


# ── When ────────────────────────────────────────────────────


@when("I run skill show for the skill with unregistered include")
def step_run_show_unregistered_include(context):
    context.result = context.runner.invoke(skill_app, ["show", context.skill_name])


@when("I run skill show with capability summary raising ValueError")
def step_run_show_capability_error(context):
    with patch.object(
        context.service,
        "compute_capability_summary",
        side_effect=ValueError("boom"),
    ):
        context.result = context.runner.invoke(skill_app, ["show", context.skill_name])


@when("I run skill show with dependents returning actors")
def step_run_show_dependent_actors(context):
    with patch.object(
        context.service,
        "get_dependents",
        return_value={"skills": [], "actors": ["actor/alpha", "actor/beta"]},
    ):
        context.result = context.runner.invoke(skill_app, ["show", context.skill_name])


@when("I run skill tools for the agent_skill skill")
def step_run_tools_agent_skill(context):
    context.result = context.runner.invoke(skill_app, ["tools", context.skill_name])


@when("I run skill remove with dependents returning actors")
def step_run_remove_with_actor_dependents(context):
    with patch.object(
        context.service,
        "get_dependents",
        return_value={
            "skills": [],
            "actors": ["actor/gamma", "actor/delta"],
        },
    ):
        context.result = context.runner.invoke(
            skill_app,
            ["remove", context.skill_name, "--yes"],
        )


# ── Then ────────────────────────────────────────────────────


@then("the show output contains the not registered marker")
def step_show_not_registered(context):
    assert context.result.exit_code == 0, (
        f"exit_code={context.result.exit_code}\n{context.result.output}"
    )
    assert "not registered" in context.result.output


@then("the show output contains OK and no capability panel")
def step_show_ok_no_capability(context):
    assert context.result.exit_code == 0, (
        f"exit_code={context.result.exit_code}\n{context.result.output}"
    )
    assert "OK" in context.result.output
    # The capability panel should be absent because the exception was caught
    assert "Capability Summary" not in context.result.output


@then("the show output contains the actors reference line")
def step_show_actors_reference(context):
    assert context.result.exit_code == 0, (
        f"exit_code={context.result.exit_code}\n{context.result.output}"
    )
    assert "actor/alpha" in context.result.output
    assert "actor/beta" in context.result.output
    assert "Actors" in context.result.output


@then("the tools output contains agent_skill source type")
def step_tools_agent_skill_source(context):
    assert context.result.exit_code == 0, (
        f"exit_code={context.result.exit_code}\n{context.result.output}"
    )
    assert "agent_skill" in context.result.output


@then("the remove output contains the actor dependency warning")
def step_remove_actor_warning(context):
    assert context.result.exit_code == 0, (
        f"exit_code={context.result.exit_code}\n{context.result.output}"
    )
    assert "actor(s) reference this skill" in context.result.output
    assert "actor/gamma" in context.result.output
    assert "actor/delta" in context.result.output
