"""Step definitions for predictive_error_prevention.feature.

Exercises the Error Pattern Database (Layer 4: Predictive Error Prevention)
including recording, matching, formatting, statistics, and keyword extraction.
"""

from __future__ import annotations

from typing import Any

from behave import given, then, when

from cleveragents.application.services.error_pattern_service import (
    ErrorPatternService,
)
from cleveragents.domain.models.core.error_pattern import (
    ErrorPattern,
    PreventiveGuidance,
)
from cleveragents.infrastructure.database.error_pattern_repository import (
    ErrorPatternRepository,
)


@given("a fresh error pattern service")
def step_pep_fresh_service(context: Any) -> None:
    context.pep_service = ErrorPatternService()
    context.pep_last_pattern = None
    context.pep_guidance: PreventiveGuidance | None = None
    context.pep_statistics: dict[str, int | float] | None = None


@given(
    'a recorded pattern "{pattern}" with preventive check "{check}" and keywords "{keywords}"'
)
def step_pep_record_pattern_with_check_and_keywords(
    context: Any, pattern: str, check: str, keywords: str
) -> None:
    kw_tuple = tuple(k.strip() for k in keywords.split(","))
    context.pep_last_pattern = context.pep_service.record_failure(
        pattern_text=pattern,
        failure_description=f"Historical failure for {pattern}",
        preventive_checks=(check,),
        keywords=kw_tuple,
    )


@given('a recorded pattern "{pattern}" with preventive check "{check}"')
def step_pep_record_pattern_with_check(context: Any, pattern: str, check: str) -> None:
    context.pep_last_pattern = context.pep_service.record_failure(
        pattern_text=pattern,
        failure_description=f"Historical failure for {pattern}",
        preventive_checks=(check,),
    )


@when('I record a failure with pattern "{pattern}" and failure "{failure}"')
def step_pep_record_failure(context: Any, pattern: str, failure: str) -> None:
    context.pep_last_pattern = context.pep_service.record_failure(
        pattern_text=pattern,
        failure_description=failure,
    )


@when('I match context "{text}"')
def step_pep_match_context(context: Any, text: str) -> None:
    context.pep_guidance = context.pep_service.match_patterns(text)


@when("I request error pattern statistics")
def step_pep_request_statistics(context: Any) -> None:
    context.pep_statistics = context.pep_service.get_statistics()


@then("the error pattern database should contain {count:d} pattern")
def step_pep_assert_pattern_count(context: Any, count: int) -> None:
    patterns = context.pep_service.list_patterns()
    assert len(patterns) == count, f"Expected {count} patterns, got {len(patterns)}"


@then("the pattern should have frequency {freq:d}")
def step_pep_assert_frequency(context: Any, freq: int) -> None:
    patterns = context.pep_service.list_patterns()
    assert len(patterns) > 0, "No patterns found"
    actual = patterns[0].frequency
    assert actual == freq, f"Expected frequency {freq}, got {actual}"


@then("the pattern should have {count:d} historical failures")
def step_pep_assert_historical_failures_count(context: Any, count: int) -> None:
    patterns = context.pep_service.list_patterns()
    assert len(patterns) > 0, "No patterns found"
    actual = len(patterns[0].historical_failures)
    assert actual == count, f"Expected {count} historical failures, got {actual}"


@then('preventive guidance should contain "{text}"')
def step_pep_assert_guidance_contains(context: Any, text: str) -> None:
    assert context.pep_guidance is not None, "No guidance available"
    all_checks = context.pep_guidance.preventive_checks
    assert any(text in c for c in all_checks), (
        f"Expected guidance to contain '{text}', got {all_checks}"
    )


@then("preventive guidance should be empty")
def step_pep_assert_guidance_empty(context: Any) -> None:
    assert context.pep_guidance is not None, "No guidance available"
    assert not context.pep_guidance.has_guidance, (
        f"Expected empty guidance, got {context.pep_guidance.preventive_checks}"
    )


@then('the formatted guidance should contain "{text}"')
def step_pep_assert_formatted_contains(context: Any, text: str) -> None:
    assert context.pep_guidance is not None, "No guidance available"
    formatted = context.pep_guidance.format_for_context()
    assert text in formatted, (
        f"Expected formatted guidance to contain '{text}', got: {formatted}"
    )


@then("the statistics should show {count:d} total patterns")
def step_pep_assert_stats_total(context: Any, count: int) -> None:
    assert context.pep_statistics is not None, "No statistics available"
    actual = context.pep_statistics["total_patterns"]
    assert actual == count, f"Expected {count} total patterns, got {actual}"


@then('the recorded pattern should have keywords including "{keyword}"')
def step_pep_assert_keyword(context: Any, keyword: str) -> None:
    assert context.pep_last_pattern is not None, "No pattern recorded"
    keywords_lower = [k.lower() for k in context.pep_last_pattern.keywords]
    assert keyword.lower() in keywords_lower, (
        f"Expected keyword '{keyword}' in {context.pep_last_pattern.keywords}"
    )


@then("the recorded pattern can be retrieved by its ID")
def step_pep_retrieve_by_id(context: Any) -> None:
    assert context.pep_last_pattern is not None, "No pattern recorded"
    repo = ErrorPatternRepository()
    repo.create(context.pep_last_pattern)
    retrieved = repo.get(context.pep_last_pattern.pattern_id)
    assert retrieved is not None, "Pattern not found by ID"
    assert retrieved.pattern_id == context.pep_last_pattern.pattern_id


@when("I delete the last recorded pattern")
def step_pep_delete_last_pattern(context: Any) -> None:
    assert context.pep_last_pattern is not None, "No pattern recorded"
    # Access the internal repo to delete
    deleted = context.pep_service._repo.delete(context.pep_last_pattern.pattern_id)
    assert deleted, "Delete returned False"


@then("the error pattern database should contain {count:d} patterns")
def step_pep_assert_pattern_count_plural(context: Any, count: int) -> None:
    patterns = context.pep_service.list_patterns()
    assert len(patterns) == count, f"Expected {count} patterns, got {len(patterns)}"


@given('a recorded pattern with no keywords for "{pattern}" with check "{check}"')
def step_pep_record_pattern_no_keywords(context: Any, pattern: str, check: str) -> None:
    ep = ErrorPattern(
        pattern=pattern,
        historical_failures=("Initial failure",),
        preventive_checks=(check,),
        keywords=(),  # No keywords — forces fallback matching
    )
    context.pep_service._repo.create(ep)
    context.pep_last_pattern = ep
