"""Step definitions for A2A clients coverage boost scenarios.

Covers:
- Protocol default method bodies (the ``...`` expression on lines 28, 36, 52, 63, 74, 90, 101)
- Stub validation branches for empty/non-string inputs (lines 149, 159, 186)
"""

from __future__ import annotations

import contextlib

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

with contextlib.suppress(ImportError):
    from cleveragents.a2a.clients import (
        AuthClient,
        RemoteExecutionClient,
        ServerClient,
        StubAuthClient,
        StubRemoteExecutionClient,
    )

# ---------------------------------------------------------------------------
# Concrete subclasses that inherit Protocol default method bodies
# ---------------------------------------------------------------------------


class _ConcreteServerClient(ServerClient):
    """Minimal concrete subclass — inherits the ``...`` default bodies."""

    pass


class _ConcreteRemoteExecutionClient(RemoteExecutionClient):
    """Minimal concrete subclass — inherits the ``...`` default bodies."""

    pass


class _ConcreteAuthClient(AuthClient):
    """Minimal concrete subclass — inherits the ``...`` default bodies."""

    pass


# ---------------------------------------------------------------------------
# Given steps — Protocol concrete subclasses
# ---------------------------------------------------------------------------


@given("a concrete subclass of ServerClient protocol")
def step_concrete_server_client(context: Context) -> None:
    context.concrete_server = _ConcreteServerClient()
    context.call_error = None


@given("a concrete subclass of RemoteExecutionClient protocol")
def step_concrete_exec_client(context: Context) -> None:
    context.concrete_exec = _ConcreteRemoteExecutionClient()
    context.call_error = None


@given("a concrete subclass of AuthClient protocol")
def step_concrete_auth_client(context: Context) -> None:
    context.concrete_auth = _ConcreteAuthClient()
    context.call_error = None


# ---------------------------------------------------------------------------
# When steps — call Protocol default method bodies
# ---------------------------------------------------------------------------


@when("I call health_check on the concrete server client")
def step_call_concrete_health_check(context: Context) -> None:
    try:
        context.call_result = context.concrete_server.health_check()
    except Exception as exc:
        context.call_error = exc


@when("I call get_version on the concrete server client")
def step_call_concrete_get_version(context: Context) -> None:
    try:
        context.call_result = context.concrete_server.get_version()
    except Exception as exc:
        context.call_error = exc


@when("I call execute_plan on the concrete execution client")
def step_call_concrete_execute_plan(context: Context) -> None:
    try:
        context.call_result = context.concrete_exec.execute_plan("test-plan")
    except Exception as exc:
        context.call_error = exc


@when("I call get_plan_status on the concrete execution client")
def step_call_concrete_get_plan_status(context: Context) -> None:
    try:
        context.call_result = context.concrete_exec.get_plan_status("test-plan")
    except Exception as exc:
        context.call_error = exc


@when("I call cancel_plan on the concrete execution client")
def step_call_concrete_cancel_plan(context: Context) -> None:
    try:
        context.call_result = context.concrete_exec.cancel_plan("test-plan")
    except Exception as exc:
        context.call_error = exc


@when("I call authenticate on the concrete auth client")
def step_call_concrete_authenticate(context: Context) -> None:
    try:
        context.call_result = context.concrete_auth.authenticate("tok_test")
    except Exception as exc:
        context.call_error = exc


@when("I call validate_token on the concrete auth client")
def step_call_concrete_validate_token(context: Context) -> None:
    try:
        context.call_result = context.concrete_auth.validate_token("tok_test")
    except Exception as exc:
        context.call_error = exc


# ---------------------------------------------------------------------------
# Then step — Protocol calls complete without error
# ---------------------------------------------------------------------------


@then("the call should complete without error")
def step_call_completes(context: Context) -> None:
    assert context.call_error is None, (
        f"Expected no error but got: {context.call_error!r}"
    )


# ---------------------------------------------------------------------------
# Given steps — Stub instances for validation branch coverage
# ---------------------------------------------------------------------------


@given("a fresh StubRemoteExecutionClient for coverage")
def step_fresh_stub_exec(context: Context) -> None:
    context.cov_stub_exec = StubRemoteExecutionClient()
    context.cov_caught_error = None


@given("a fresh StubAuthClient for coverage")
def step_fresh_stub_auth(context: Context) -> None:
    context.cov_stub_auth = StubAuthClient()
    context.cov_caught_error = None


# ---------------------------------------------------------------------------
# When steps — empty string inputs to stubs
# ---------------------------------------------------------------------------


@when("I call get_plan_status with empty plan_id on the stub")
def step_stub_get_plan_status_empty(context: Context) -> None:
    try:
        context.cov_stub_exec.get_plan_status("")
    except ValueError as exc:
        context.cov_caught_error = exc


@when("I call cancel_plan with empty plan_id on the stub")
def step_stub_cancel_plan_empty(context: Context) -> None:
    try:
        context.cov_stub_exec.cancel_plan("")
    except ValueError as exc:
        context.cov_caught_error = exc


@when("I call validate_token with empty token on the stub")
def step_stub_validate_token_empty(context: Context) -> None:
    try:
        context.cov_stub_auth.validate_token("")
    except ValueError as exc:
        context.cov_caught_error = exc


# ---------------------------------------------------------------------------
# When steps — non-string type inputs to stubs
# ---------------------------------------------------------------------------


@when("I call get_plan_status with a non-string plan_id on the stub")
def step_stub_get_plan_status_non_string(context: Context) -> None:
    try:
        context.cov_stub_exec.get_plan_status(12345)  # type: ignore[arg-type]
    except ValueError as exc:
        context.cov_caught_error = exc


@when("I call cancel_plan with a non-string plan_id on the stub")
def step_stub_cancel_plan_non_string(context: Context) -> None:
    try:
        context.cov_stub_exec.cancel_plan(12345)  # type: ignore[arg-type]
    except ValueError as exc:
        context.cov_caught_error = exc


@when("I call validate_token with a non-string token on the stub")
def step_stub_validate_token_non_string(context: Context) -> None:
    try:
        context.cov_stub_auth.validate_token(12345)  # type: ignore[arg-type]
    except ValueError as exc:
        context.cov_caught_error = exc


# ---------------------------------------------------------------------------
# Then steps — ValueError assertions
# ---------------------------------------------------------------------------


@then("a ValueError should be raised with plan_id validation message")
def step_value_error_plan_id_msg(context: Context) -> None:
    assert context.cov_caught_error is not None, (
        "Expected ValueError but none was raised"
    )
    assert isinstance(context.cov_caught_error, ValueError), (
        f"Expected ValueError, got {type(context.cov_caught_error).__name__}"
    )
    assert "plan_id" in str(context.cov_caught_error), (
        f"Expected 'plan_id' in error message, got: {context.cov_caught_error}"
    )


@then("a ValueError should be raised with token validation message")
def step_value_error_token_msg(context: Context) -> None:
    assert context.cov_caught_error is not None, (
        "Expected ValueError but none was raised"
    )
    assert isinstance(context.cov_caught_error, ValueError), (
        f"Expected ValueError, got {type(context.cov_caught_error).__name__}"
    )
    assert "token" in str(context.cov_caught_error), (
        f"Expected 'token' in error message, got: {context.cov_caught_error}"
    )
