"""Step definitions for Temporal Data Model — service steps."""

from __future__ import annotations

from typing import Any

from behave import given, then, when

from cleveragents.application.services.temporal_service import TemporalService
from cleveragents.domain.models.acms.temporal_stubs import InMemoryTemporalBackend
from cleveragents.domain.models.acms.tiers import ContextTier
from cleveragents.domain.models.core.project import TemporalScope

__all__: list[str] = []


# ---------------------------------------------------------------------------
# TemporalService steps
# ---------------------------------------------------------------------------


@given("a TemporalService with InMemoryTemporalBackend")
def step_given_temporal_service(context: Any) -> None:
    backend = InMemoryTemporalBackend()
    context.temporal_service = TemporalService(backend=backend)
    context.temporal_backend = backend


@given('I store an initial node "{uri}" for resource "{resource}" at "{path}"')
@when('I store an initial node "{uri}" for resource "{resource}" at "{path}"')
def step_when_store_initial(
    context: Any,
    uri: str,
    resource: str,
    path: str,
) -> None:
    context.service_node = context.temporal_service.store_initial_node(
        node_uri=uri,
        source_resource=resource,
        source_path=path,
    )


@then("the stored node should be current")
def step_then_stored_current(context: Any) -> None:
    assert context.service_node.temporal.is_current is True


@then("the stored node should have no predecessor")
def step_then_stored_no_predecessor(context: Any) -> None:
    assert context.service_node.temporal.is_revision_of is None


@when(
    'I create a service revision from "{old}" to "{new}"'
    ' for resource "{resource}" at "{path}"'
)
def step_when_service_create_revision(
    context: Any,
    old: str,
    new: str,
    resource: str,
    path: str,
) -> None:
    context.service_revision = context.temporal_service.create_revision(
        current_uri=old,
        new_node_uri=new,
        source_resource=resource,
        source_path=path,
    )


@then("the service revision node should be current")
def step_then_service_revision_current(context: Any) -> None:
    assert context.service_revision.temporal.is_current is True


@then('the service revision node should have is_revision_of "{expected}"')
def step_then_service_revision_of(context: Any, expected: str) -> None:
    assert context.service_revision.temporal.is_revision_of == expected


@when('I get the service current for "{base}"')
def step_when_service_get_current(context: Any, base: str) -> None:
    context.service_current = context.temporal_service.get_current(base)


@then('the service current node uri should be "{expected}"')
def step_then_service_current_uri(context: Any, expected: str) -> None:
    assert context.service_current is not None
    assert context.service_current.node_uri == expected


@when("I query HOT tier via the service")
def step_when_service_query_hot(context: Any) -> None:
    context.service_tier_query = context.temporal_service.query_by_tier(
        ContextTier.HOT,
    )


@when("I query HOT tier via the service with scope ALL")
def step_when_service_query_hot_all(context: Any) -> None:
    context.service_tier_query = context.temporal_service.query_by_tier(
        ContextTier.HOT,
        temporal_scope=TemporalScope.ALL,
    )


@then("the service tier query scope should be CURRENT")
def step_then_service_tier_scope_current(context: Any) -> None:
    assert context.service_tier_query.temporal_scope == TemporalScope.CURRENT


@then("the service tier query scope should be ALL")
def step_then_service_tier_scope_all(context: Any) -> None:
    assert context.service_tier_query.temporal_scope == TemporalScope.ALL


@when('I mark "{uri}" as historical via the service')
def step_when_service_mark_historical(context: Any, uri: str) -> None:
    context.service_marked = context.temporal_service.mark_historical(uri)


@then("the service marked node should not be current")
def step_then_service_marked_not_current(context: Any) -> None:
    assert context.service_marked.temporal.is_current is False


@then("storing an initial node with blank URI via the service should raise ValueError")
def step_then_service_blank_uri(context: Any) -> None:
    try:
        context.temporal_service.store_initial_node(
            node_uri="",
            source_resource="RES",
            source_path="src/a.py",
        )
        msg = "Expected ValueError"
        raise AssertionError(msg)
    except ValueError:
        pass


@then(
    "storing an initial node with blank source_resource via the service"
    " should raise ValueError"
)
def step_then_service_blank_resource(context: Any) -> None:
    try:
        context.temporal_service.store_initial_node(
            node_uri="uko:test",
            source_resource="",
            source_path="src/a.py",
        )
        msg = "Expected ValueError"
        raise AssertionError(msg)
    except ValueError:
        pass


@when('I get the service history for "{base}" with scope ALL')
def step_when_service_get_history_all(context: Any, base: str) -> None:
    context.service_history = context.temporal_service.get_history(
        base,
        temporal_scope=TemporalScope.ALL,
    )


@when('I get the service history for "{base}" with scope CURRENT')
def step_when_service_get_history_current(context: Any, base: str) -> None:
    context.service_history = context.temporal_service.get_history(
        base,
        temporal_scope=TemporalScope.CURRENT,
    )


@then("the service history should have {count:d} nodes")
def step_then_service_history_count(context: Any, count: int) -> None:
    assert len(context.service_history) == count, (
        f"Expected {count} nodes, got {len(context.service_history)}"
    )


@then("getting service history for blank base URI should raise ValueError")
def step_then_service_history_blank_raises(context: Any) -> None:
    try:
        context.temporal_service.get_history("")
        msg = "Expected ValueError"
        raise AssertionError(msg)
    except ValueError:
        pass


@when('I get the service revision chain for "{uri}"')
def step_when_service_get_chain(context: Any, uri: str) -> None:
    context.service_chain = context.temporal_service.get_revision_chain(uri)


@then("the service revision chain depth should be {expected:d}")
def step_then_service_chain_depth(context: Any, expected: int) -> None:
    assert context.service_chain.depth == expected, (
        f"Expected depth {expected}, got {context.service_chain.depth}"
    )


@then('the service revision chain current should be "{expected}"')
def step_then_service_chain_current(context: Any, expected: str) -> None:
    assert context.service_chain.current_uri == expected, (
        f"Expected {expected}, got {context.service_chain.current_uri}"
    )


@then("getting service revision chain for blank URI should raise ValueError")
def step_then_service_chain_blank_raises(context: Any) -> None:
    try:
        context.temporal_service.get_revision_chain("")
        msg = "Expected ValueError"
        raise AssertionError(msg)
    except ValueError:
        pass


@when("I query COLD tier via the service with scope CURRENT")
def step_when_service_query_cold_current(context: Any) -> None:
    context.service_tier_query = context.temporal_service.query_by_tier(
        ContextTier.COLD,
        temporal_scope=TemporalScope.CURRENT,
    )


@then("the service tier query should return {count:d} node")
def step_then_service_tier_query_count(context: Any, count: int) -> None:
    assert len(context.service_tier_query.nodes) == count, (
        f"Expected {count} nodes, got {len(context.service_tier_query.nodes)}"
    )


@then("the service tier query node should be current")
def step_then_service_tier_query_node_current(context: Any) -> None:
    for node in context.service_tier_query.nodes:
        assert node.temporal.is_current is True, f"Node {node.node_uri} is not current"


@then("the service retention warm hours should be {expected:d}")
def step_then_service_retention_warm(context: Any, expected: int) -> None:
    assert context.temporal_service.retention.warm_retention_hours == expected


@then("the service retention cold days should be {expected:d}")
def step_then_service_retention_cold(context: Any, expected: int) -> None:
    assert context.temporal_service.retention.cold_retention_days == expected


# ---------------------------------------------------------------------------
# Diff-coverage steps (WARM/COLD default scopes)
# ---------------------------------------------------------------------------


@when("I query WARM tier via the service")
def step_when_service_query_warm(context: Any) -> None:
    context.service_tier_query = context.temporal_service.query_by_tier(
        ContextTier.WARM,
    )


@when("I query COLD tier via the service")
def step_when_service_query_cold(context: Any) -> None:
    context.service_tier_query = context.temporal_service.query_by_tier(
        ContextTier.COLD,
    )


@then("the service tier query scope should be RECENT")
def step_then_service_tier_scope_recent(context: Any) -> None:
    assert context.service_tier_query.temporal_scope == TemporalScope.RECENT


# ---------------------------------------------------------------------------
# Edge-case guards (Round 3 bug-hunt fixes)
# ---------------------------------------------------------------------------


@then(
    'creating a service revision from "{uri}" to itself should raise ValueError',
)
def step_then_service_same_uri_raises(context: Any, uri: str) -> None:
    try:
        context.temporal_service.create_revision(
            current_uri=uri,
            new_node_uri=uri,
            source_resource="RES001",
            source_path="src/foo.py",
        )
        msg = "Expected ValueError for same-URI service revision"
        raise AssertionError(msg)
    except ValueError:
        pass


@then(
    'marking "{uri}" as historical again via the service should raise ValueError',
)
def step_then_service_mark_historical_again_raises(
    context: Any,
    uri: str,
) -> None:
    try:
        context.temporal_service.mark_historical(uri)
        msg = "Expected ValueError for already-historical node"
        raise AssertionError(msg)
    except ValueError:
        pass


@then("creating a TemporalService with None backend should raise TypeError")
def step_then_service_none_backend(context: Any) -> None:
    try:
        TemporalService(backend=None)  # type: ignore[arg-type]
        msg = "Expected TypeError for None backend"
        raise AssertionError(msg)
    except TypeError:
        pass
