"""Step definitions for change_model_coverage_boost.feature.

Targets uncovered lines in change.py:
- Line 268: DELETE branch of ChangeEntry.has_integrity_hashes
- Lines 487, 491, 499, 503: InvocationTracker Protocol method bodies
- Lines 560, 566, 570, 574, 578: ChangeSetStore Protocol method bodies
"""

from __future__ import annotations

from typing import Any

from behave import given, then, when

from cleveragents.domain.models.core.change import (
    ChangeEntry,
    ChangeOperation,
    ChangeSetStore,
    InvocationTracker,
    ToolInvocation,
)

__all__: list[str] = []


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------


def _base_entry_kwargs() -> dict[str, Any]:
    return {
        "plan_id": "plan-cov",
        "resource_id": "res-cov",
        "tool_name": "builtin/file-write",
        "path": "src/coverage.py",
    }


# Bare subclasses that inherit Protocol default (ellipsis) method bodies.
class _BareInvocationTracker(InvocationTracker):
    pass


class _BareChangeSetStore(ChangeSetStore):
    pass


# ---------------------------------------------------------------------------
# DELETE has_integrity_hashes (line 268)
# ---------------------------------------------------------------------------


@given('a DELETE ChangeEntry with before_hash "{h}"')
def step_delete_entry_with_before_hash(context: Any, h: str) -> None:
    context.entry = ChangeEntry(
        **_base_entry_kwargs(),
        operation=ChangeOperation.DELETE,
        before_hash=h,
    )


@given("a DELETE ChangeEntry without before_hash")
def step_delete_entry_without_before_hash(context: Any) -> None:
    context.entry = ChangeEntry(
        **_base_entry_kwargs(),
        operation=ChangeOperation.DELETE,
    )


@then("the entry has_integrity_hashes should be true")
def step_entry_integrity_true(context: Any) -> None:
    assert context.entry.has_integrity_hashes is True


@then("the entry has_integrity_hashes should be false")
def step_entry_integrity_false(context: Any) -> None:
    assert context.entry.has_integrity_hashes is False


# ---------------------------------------------------------------------------
# InvocationTracker Protocol method bodies (lines 487, 491, 499, 503)
# ---------------------------------------------------------------------------


@given("a bare InvocationTracker subclass instance")
def step_bare_invocation_tracker(context: Any) -> None:
    context.bare_tracker = _BareInvocationTracker()


@when("I call track on the protocol with a ToolInvocation")
def step_call_track(context: Any) -> None:
    inv = ToolInvocation(plan_id="plan-proto", tool_name="test/tool")
    context.track_result = context.bare_tracker.track(inv)


@then("track should return None")
def step_track_returns_none(context: Any) -> None:
    assert context.track_result is None


@when('I call get_invocations on the protocol with plan_id "{pid}"')
def step_call_get_invocations(context: Any, pid: str) -> None:
    context.get_inv_result = context.bare_tracker.get_invocations(pid)


@then("get_invocations should return None")
def step_get_invocations_returns_none(context: Any) -> None:
    assert context.get_inv_result is None


@when(
    'I call get_invocations_for_skill on the protocol with plan_id "{pid}" and skill "{sk}"'
)
def step_call_get_invocations_for_skill(context: Any, pid: str, sk: str) -> None:
    context.get_inv_skill_result = context.bare_tracker.get_invocations_for_skill(
        pid, sk
    )


@then("get_invocations_for_skill should return None")
def step_get_invocations_for_skill_returns_none(context: Any) -> None:
    assert context.get_inv_skill_result is None


@when('I call get_changes on the protocol with plan_id "{pid}"')
def step_call_get_changes(context: Any, pid: str) -> None:
    context.get_changes_result = context.bare_tracker.get_changes(pid)


@then("get_changes should return None")
def step_get_changes_returns_none(context: Any) -> None:
    assert context.get_changes_result is None


# ---------------------------------------------------------------------------
# ChangeSetStore Protocol method bodies (lines 560, 566, 570, 574, 578)
# ---------------------------------------------------------------------------


@given("a bare ChangeSetStore subclass instance")
def step_bare_changeset_store(context: Any) -> None:
    context.bare_store = _BareChangeSetStore()


@when('I call start on the store protocol with plan_id "{pid}"')
def step_call_store_start(context: Any, pid: str) -> None:
    context.store_start_result = context.bare_store.start(pid)


@then("start should return None")
def step_store_start_returns_none(context: Any) -> None:
    assert context.store_start_result is None


@when(
    'I call record on the store protocol with changeset_id "{csid}" and a ChangeEntry'
)
def step_call_store_record(context: Any, csid: str) -> None:
    kwargs = _base_entry_kwargs()
    kwargs["path"] = "proto.py"
    entry = ChangeEntry(
        **kwargs,
        operation=ChangeOperation.CREATE,
    )
    context.store_record_result = context.bare_store.record(csid, entry)


@then("record should return None")
def step_store_record_returns_none(context: Any) -> None:
    assert context.store_record_result is None


@when('I call get on the store protocol with changeset_id "{csid}"')
def step_call_store_get(context: Any, csid: str) -> None:
    context.store_get_result = context.bare_store.get(csid)


@then("protocol get should return None")
def step_store_get_returns_none(context: Any) -> None:
    assert context.store_get_result is None


@when('I call get_for_plan on the store protocol with plan_id "{pid}"')
def step_call_store_get_for_plan(context: Any, pid: str) -> None:
    context.store_get_for_plan_result = context.bare_store.get_for_plan(pid)


@then("get_for_plan should return None")
def step_store_get_for_plan_returns_none(context: Any) -> None:
    assert context.store_get_for_plan_result is None


@when('I call summarize on the store protocol with changeset_id "{csid}"')
def step_call_store_summarize(context: Any, csid: str) -> None:
    context.store_summarize_result = context.bare_store.summarize(csid)


@then("summarize should return None")
def step_store_summarize_returns_none(context: Any) -> None:
    assert context.store_summarize_result is None
