"""Step definitions for diagnostics_provider_coverage.feature.

Tests that _check_providers() in system.py reports diagnostic status for
all 9 supported providers: openai, anthropic, google, azure, openrouter,
gemini, cohere, groq, together.
"""

from __future__ import annotations

from unittest.mock import patch

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

from features.mocks.settings_mock import make_settings_mock

# ---------------------------------------------------------------------------
# Given
# ---------------------------------------------------------------------------


@given("the diagnostics provider check module is loaded")
def step_provider_check_module_loaded(context: Context) -> None:
    context.provider_results = None
    context.configured_providers: set[str] = set()


# ---------------------------------------------------------------------------
# When
# ---------------------------------------------------------------------------


@when("I call check_providers with no providers configured")
def step_check_providers_none_configured(context: Context) -> None:
    from cleveragents.cli.commands.system import _check_providers

    ms = make_settings_mock(configured_providers=set())
    with patch("cleveragents.config.settings.get_settings", return_value=ms):
        context.provider_results = _check_providers()


@when('I call check_providers with "{provider}" configured')
def step_check_providers_one_configured(context: Context, provider: str) -> None:
    from cleveragents.cli.commands.system import _check_providers

    ms = make_settings_mock(configured_providers={provider})
    with patch("cleveragents.config.settings.get_settings", return_value=ms):
        context.provider_results = _check_providers()


# ---------------------------------------------------------------------------
# Then — count assertions
# ---------------------------------------------------------------------------


@then("the provider check results should contain exactly {count:d} entries")
def step_assert_result_count(context: Context, count: int) -> None:
    results = context.provider_results
    assert results is not None, "provider_results is None"
    actual = len(results)
    assert actual == count, (
        f"Expected exactly {count} provider check entries, got {actual}. "
        f"Entries: {[r['name'] for r in results]}"
    )


# ---------------------------------------------------------------------------
# Then — provider presence assertions
# ---------------------------------------------------------------------------


@then('the provider check results should include provider "{provider}"')
def step_assert_provider_present(context: Context, provider: str) -> None:
    results = context.provider_results
    assert results is not None, "provider_results is None"
    names_lower = [r["name"].lower() for r in results]
    assert any(provider.lower() in name for name in names_lower), (
        f"Expected provider '{provider}' in results, but got: "
        f"{[r['name'] for r in results]}"
    )


def _find_provider_result(results: list[dict], provider: str) -> dict | None:
    """Find the result entry for a given provider name."""
    for r in results:
        if provider.lower() in r["name"].lower():
            return r
    return None


# ---------------------------------------------------------------------------
# Then — per-provider status/details/recommendation assertions
# ---------------------------------------------------------------------------


@then(
    'the provider check result for "{provider}" should have status "{expected_status}"'
)
def step_assert_provider_status(
    context: Context, provider: str, expected_status: str
) -> None:
    results = context.provider_results
    assert results is not None, "provider_results is None"
    entry = _find_provider_result(results, provider)
    assert entry is not None, (
        f"No result found for provider '{provider}'. "
        f"Available: {[r['name'] for r in results]}"
    )
    actual = str(entry["status"])
    assert actual == expected_status, (
        f"Provider '{provider}': expected status '{expected_status}', got '{actual}'"
    )


@then(
    'the provider check result for "{provider}" should have details "{expected_details}"'
)
def step_assert_provider_details(
    context: Context, provider: str, expected_details: str
) -> None:
    results = context.provider_results
    assert results is not None, "provider_results is None"
    entry = _find_provider_result(results, provider)
    assert entry is not None, (
        f"No result found for provider '{provider}'. "
        f"Available: {[r['name'] for r in results]}"
    )
    actual = entry["details"]
    assert actual == expected_details, (
        f"Provider '{provider}': expected details '{expected_details}', got '{actual}'"
    )


@then('the provider check result for "{provider}" should have no recommendation')
def step_assert_provider_no_recommendation(context: Context, provider: str) -> None:
    results = context.provider_results
    assert results is not None, "provider_results is None"
    entry = _find_provider_result(results, provider)
    assert entry is not None, (
        f"No result found for provider '{provider}'. "
        f"Available: {[r['name'] for r in results]}"
    )
    rec = entry.get("recommendation")
    assert rec is None, (
        f"Provider '{provider}': expected no recommendation, got '{rec}'"
    )


@then(
    'the provider check result for "{provider}" should have a recommendation mentioning "{env_var}"'
)
def step_assert_provider_recommendation_mentions(
    context: Context, provider: str, env_var: str
) -> None:
    results = context.provider_results
    assert results is not None, "provider_results is None"
    entry = _find_provider_result(results, provider)
    assert entry is not None, (
        f"No result found for provider '{provider}'. "
        f"Available: {[r['name'] for r in results]}"
    )
    rec = entry.get("recommendation")
    assert rec is not None, (
        f"Provider '{provider}': expected a recommendation mentioning '{env_var}', "
        f"but recommendation is None"
    )
    assert env_var in rec, (
        f"Provider '{provider}': expected recommendation to mention '{env_var}', "
        f"got '{rec}'"
    )
