"""Step definitions for Plan Preflight Guardrail coverage-boost scenarios.

Targets the uncovered lines identified in coverage.xml:
  - Lines 52-53: PreflightCheckResult.__repr__
  - Lines 86-90: PreflightReport.format_report
  - Lines 166-169: check_action_schema with action_name=None
  - Line 221: check_skill_tool_existence with missing skills
"""

from __future__ import annotations

from behave import given, then, when
from behave.runner import Context

from cleveragents.application.services.plan_preflight_guardrail import (
    PlanPreflightGuardrail,
    PreflightCheckName,
    PreflightCheckResult,
    PreflightRejection,
    PreflightReport,
)

# ---------------------------------------------------------------------------
# Givens
# ---------------------------------------------------------------------------


@given("a passing PreflightCheckResult for action_schema_validation")
def step_given_passing_result(context: Context) -> None:
    context.cb_check_result = PreflightCheckResult(
        PreflightCheckName.ACTION_SCHEMA,
        True,
        "Action 'deploy' found and valid",
    )


@given('a failing PreflightCheckResult for actor_availability with message "{msg}"')
def step_given_failing_result(context: Context, msg: str) -> None:
    context.cb_check_result = PreflightCheckResult(
        PreflightCheckName.ACTOR_AVAILABILITY,
        False,
        msg,
    )


@given("a PreflightReport with one passing and one failing check result")
def step_given_mixed_report(context: Context) -> None:
    report = PreflightReport()
    report.add(
        PreflightCheckResult(
            PreflightCheckName.ACTION_SCHEMA,
            True,
            "Action 'deploy' found and valid",
        )
    )
    report.add(
        PreflightCheckResult(
            PreflightCheckName.ACTOR_AVAILABILITY,
            False,
            "Missing actor roles: estimation",
        )
    )
    context.cb_report = report


@given("a PreflightReport with only passing check results")
def step_given_all_pass_report(context: Context) -> None:
    report = PreflightReport()
    report.add(
        PreflightCheckResult(
            PreflightCheckName.ACTION_SCHEMA,
            True,
            "Action 'deploy' found and valid",
        )
    )
    report.add(
        PreflightCheckResult(
            PreflightCheckName.AUTOMATION_POLICY,
            True,
            "Automation profile permits execution",
        )
    )
    context.cb_report = report


@given("a fresh plan preflight guardrail instance")
def step_given_fresh_guardrail(context: Context) -> None:
    context.cb_guardrail = PlanPreflightGuardrail()
    context.cb_check_result = None
    context.cb_rejection = None
    context.cb_skill_registry: dict[str, object] = {}


@given('a skill registry containing only "{name}"')
def step_given_skill_registry_one(context: Context, name: str) -> None:
    context.cb_skill_registry = {name: {"name": name}}


@given(
    "a fresh plan preflight guardrail instance with all registries populated but no action name"
)
def step_given_guardrail_no_action_name(context: Context) -> None:
    context.cb_guardrail = PlanPreflightGuardrail()
    context.cb_actor_registry = {
        role: {"role": role} for role in PlanPreflightGuardrail.ACTOR_ROLES
    }
    context.cb_automation_profile = {"name": "auto"}
    context.cb_rejection = None


# ---------------------------------------------------------------------------
# Whens
# ---------------------------------------------------------------------------


@when("I get the repr of the check result")
def step_when_get_repr(context: Context) -> None:
    context.cb_repr_str = repr(context.cb_check_result)


@when("I format the report")
def step_when_format_report(context: Context) -> None:
    context.cb_formatted = context.cb_report.format_report()


@when("I check action schema with no action name")
def step_when_check_action_none(context: Context) -> None:
    context.cb_check_result = context.cb_guardrail.check_action_schema(
        None, {"some-action": {"name": "some-action"}}
    )


@when('I check skill/tool existence for skills "{skills_csv}"')
def step_when_check_skills(context: Context, skills_csv: str) -> None:
    skill_names = tuple(s.strip() for s in skills_csv.split(","))
    context.cb_check_result = context.cb_guardrail.check_skill_tool_existence(
        tool_names=(),
        tool_registry={},
        skill_names=skill_names,
        skill_registry=context.cb_skill_registry,
    )


@when(
    'I check skill/tool existence for tools "{tools}" and skills "{skills}" with empty registries'
)
def step_when_check_both_missing(context: Context, tools: str, skills: str) -> None:
    tool_names = tuple(t.strip() for t in tools.split(","))
    skill_names = tuple(s.strip() for s in skills.split(","))
    context.cb_check_result = context.cb_guardrail.check_skill_tool_existence(
        tool_names=tool_names,
        tool_registry={},
        skill_names=skill_names,
        skill_registry={},
    )


@when("I run all preflight checks with action_name as None")
def step_when_run_all_none_action(context: Context) -> None:
    try:
        context.cb_guardrail.run_all_checks(
            action_name=None,
            action_registry={},
            actor_registry=context.cb_actor_registry,
            automation_profile=context.cb_automation_profile,
        )
        context.cb_rejection = None
    except PreflightRejection as exc:
        context.cb_rejection = exc


# ---------------------------------------------------------------------------
# Thens
# ---------------------------------------------------------------------------


@then('the repr should contain "{text}"')
def step_then_repr_contains(context: Context, text: str) -> None:
    assert text in context.cb_repr_str, (
        f"Expected '{text}' in repr, got: {context.cb_repr_str}"
    )


@then('the formatted report should start with "{prefix}"')
def step_then_report_starts_with(context: Context, prefix: str) -> None:
    assert context.cb_formatted.startswith(prefix), (
        f"Expected report to start with '{prefix}', got: {context.cb_formatted[:80]}"
    )


@then("the formatted report should contain a PASS line")
def step_then_report_has_pass(context: Context) -> None:
    assert "[PASS]" in context.cb_formatted, (
        f"Expected [PASS] in report, got:\n{context.cb_formatted}"
    )


@then("the formatted report should contain a FAIL line")
def step_then_report_has_fail(context: Context) -> None:
    assert "[FAIL]" in context.cb_formatted, (
        f"Expected [FAIL] in report, got:\n{context.cb_formatted}"
    )


@then('the formatted report should not contain "{text}"')
def step_then_report_not_contains(context: Context, text: str) -> None:
    assert text not in context.cb_formatted, (
        f"Did not expect '{text}' in report, but found it:\n{context.cb_formatted}"
    )


@then("the action schema check should fail")
def step_then_action_check_fails(context: Context) -> None:
    result = context.cb_check_result
    assert result is not None, "No check result recorded"
    assert result.passed is False, f"Expected FAIL but got PASS: {result.message}"
    assert result.check == PreflightCheckName.ACTION_SCHEMA


@then('the action schema check message should contain "{text}"')
def step_then_action_msg_contains(context: Context, text: str) -> None:
    assert text in context.cb_check_result.message, (
        f"Expected '{text}' in message, got: {context.cb_check_result.message}"
    )


@then("the skill tool check should fail")
def step_then_skill_check_fails(context: Context) -> None:
    result = context.cb_check_result
    assert result is not None, "No check result recorded"
    assert result.passed is False, f"Expected FAIL but got PASS: {result.message}"
    assert result.check == PreflightCheckName.SKILL_TOOL_EXISTENCE


@then('the skill tool check message should contain "{text}"')
def step_then_skill_msg_contains(context: Context, text: str) -> None:
    assert text in context.cb_check_result.message, (
        f"Expected '{text}' in message, got: {context.cb_check_result.message}"
    )


@then('a preflight rejection should be raised for "{check_name}"')
def step_then_rejection_for_check(context: Context, check_name: str) -> None:
    assert context.cb_rejection is not None, (
        "Expected PreflightRejection but none was raised"
    )
    assert context.cb_rejection.check.value == check_name, (
        f"Expected check '{check_name}', got '{context.cb_rejection.check.value}'"
    )


@then('the preflight rejection message should contain "{text}"')
def step_then_rejection_msg_contains(context: Context, text: str) -> None:
    assert context.cb_rejection is not None, "No rejection recorded"
    assert text in str(context.cb_rejection), (
        f"Expected '{text}' in rejection message, got: {context.cb_rejection}"
    )
