"""Step definitions for resource-type inheritance: field resolution, merging, polymorphism.

Covers ADR-042 sections:
2. Field resolution
3. Collection merging
5. Polymorphism
"""

from __future__ import annotations

from typing import Any

from _inheritance_test_helpers import (
    _NOOP_HANDLER,
    _ensure_registry,
    _ensure_tool_registry,
    _make_child_entry,
    _make_root_entry,
    _names_from_csv,
)
from behave import given, then, when

from cleveragents.resource.inheritance import (
    find_subtypes,
    is_subtype_of,
    resolve_fields,
)
from cleveragents.tool.runtime import ToolSpec

# ═══════════════════════════════════════════════════════════════
# 2. Field resolution — GIVEN / WHEN / THEN
# ═══════════════════════════════════════════════════════════════


@given('a type-inherit registry with parent "{name}" description "{desc}"')
def step_registry_parent_with_desc(context: Any, name: str, desc: str) -> None:
    """Add a root type with a specific description."""
    reg = _ensure_registry(context)
    reg[name] = _make_root_entry(description=desc)


@given(
    'a type-inherit child "{child}" inheriting from "{parent}" with description "{desc}"'
)
def step_registry_child_with_desc(
    context: Any, child: str, parent: str, desc: str
) -> None:
    """Add a child type with a specific description."""
    reg = _ensure_registry(context)
    reg[child] = _make_child_entry(parent, description=desc)


@given('a type-inherit registry with parent "{name}" having handler "{handler}"')
def step_registry_parent_with_handler(context: Any, name: str, handler: str) -> None:
    """Add a root type with a specific handler."""
    reg = _ensure_registry(context)
    reg[name] = _make_root_entry(handler=handler)


@given('a type-inherit child "{child}" inheriting from "{parent}" without handler')
def step_registry_child_no_handler(context: Any, child: str, parent: str) -> None:
    """Add a child type that does not set its own handler."""
    reg = _ensure_registry(context)
    reg[child] = _make_child_entry(parent)


@when('I resolve type-inherit fields for "{name}"')
def step_resolve_fields(context: Any, name: str) -> None:
    """Resolve merged fields for the given type."""
    reg = _ensure_registry(context)
    context.type_inherit_resolved = resolve_fields(name, reg)  # type: ignore[attr-defined]


@then('the type-inherit resolved description is "{desc}"')
def step_resolved_desc(context: Any, desc: str) -> None:
    """Assert the resolved description."""
    resolved = context.type_inherit_resolved  # type: ignore[attr-defined]
    assert resolved["description"] == desc, (
        f"Expected description={desc!r}, got {resolved['description']!r}"
    )


@then('the type-inherit resolved handler is "{handler}"')
def step_resolved_handler(context: Any, handler: str) -> None:
    """Assert the resolved handler."""
    resolved = context.type_inherit_resolved  # type: ignore[attr-defined]
    assert resolved.get("handler") == handler, (
        f"Expected handler={handler!r}, got {resolved.get('handler')!r}"
    )


# ═══════════════════════════════════════════════════════════════
# 3. Collection merging — GIVEN / WHEN / THEN
# ═══════════════════════════════════════════════════════════════


@given('a type-inherit parent "{name}" with cli_args "{args_csv}"')
def step_parent_cli_args(context: Any, name: str, args_csv: str) -> None:
    """Add a root type whose cli_args contain the given named arguments."""
    reg = _ensure_registry(context)
    cli_args = [{"name": n} for n in _names_from_csv(args_csv)]
    reg[name] = _make_root_entry(cli_args=cli_args)


@given(
    'a type-inherit child "{child}" inheriting from "{parent}" with cli_args "{args_csv}"'
)
def step_child_cli_args(context: Any, child: str, parent: str, args_csv: str) -> None:
    """Add a child type with its own cli_args."""
    reg = _ensure_registry(context)
    cli_args = [{"name": n} for n in _names_from_csv(args_csv)]
    reg[child] = _make_child_entry(parent, cli_args=cli_args)


@given(
    'a type-inherit child "{child}" inheriting from "{parent}" with cli_args "{args_csv}" and cli_args_replace'
)
def step_child_cli_args_replace(
    context: Any, child: str, parent: str, args_csv: str
) -> None:
    """Add a child type with cli_args and the replace flag."""
    reg = _ensure_registry(context)
    cli_args = [{"name": n} for n in _names_from_csv(args_csv)]
    reg[child] = _make_child_entry(parent, cli_args=cli_args, cli_args_replace=True)


@given('a type-inherit parent "{name}" with child_types "{types_csv}"')
def step_parent_child_types(context: Any, name: str, types_csv: str) -> None:
    """Add a root type with specific child_types."""
    reg = _ensure_registry(context)
    reg[name] = _make_root_entry(child_types=_names_from_csv(types_csv))


@given(
    'a type-inherit child "{child}" inheriting from "{parent}" with child_types "{types_csv}"'
)
def step_child_child_types(
    context: Any, child: str, parent: str, types_csv: str
) -> None:
    """Add a child type with its own child_types."""
    reg = _ensure_registry(context)
    reg[child] = _make_child_entry(parent, child_types=_names_from_csv(types_csv))


@given(
    'a type-inherit child "{child}" inheriting from "{parent}" with child_types "{types_csv}" and child_types_replace'
)
def step_child_child_types_replace(
    context: Any, child: str, parent: str, types_csv: str
) -> None:
    """Add a child type with child_types and the replace flag."""
    reg = _ensure_registry(context)
    reg[child] = _make_child_entry(
        parent, child_types=_names_from_csv(types_csv), child_types_replace=True
    )


@given('a type-inherit parent "{name}" with parent_types "{types_csv}"')
def step_parent_parent_types(context: Any, name: str, types_csv: str) -> None:
    """Add a root type with specific parent_types."""
    reg = _ensure_registry(context)
    reg[name] = _make_root_entry(parent_types=_names_from_csv(types_csv))


@given(
    'a type-inherit child "{child}" inheriting from "{parent}" with parent_types "{types_csv}"'
)
def step_child_parent_types(
    context: Any, child: str, parent: str, types_csv: str
) -> None:
    """Add a child type with its own parent_types."""
    reg = _ensure_registry(context)
    reg[child] = _make_child_entry(parent, parent_types=_names_from_csv(types_csv))


@given(
    'a type-inherit child "{child}" inheriting from "{parent}" with parent_types "{types_csv}" and parent_types_replace'
)
def step_child_parent_types_replace(
    context: Any, child: str, parent: str, types_csv: str
) -> None:
    """Add a child type with parent_types and the replace flag."""
    reg = _ensure_registry(context)
    reg[child] = _make_child_entry(
        parent, parent_types=_names_from_csv(types_csv), parent_types_replace=True
    )


@then('the type-inherit resolved cli_args names are "{expected_csv}"')
def step_resolved_cli_args_names(context: Any, expected_csv: str) -> None:
    """Assert the resolved cli_args name list (order-sensitive)."""
    resolved = context.type_inherit_resolved  # type: ignore[attr-defined]
    names = [a["name"] for a in resolved.get("cli_args", [])]
    expected = _names_from_csv(expected_csv)
    assert names == expected, f"Expected cli_args names {expected}, got {names}"


@then("the type-inherit resolved cli_args count is {count:d}")
def step_resolved_cli_args_count(context: Any, count: int) -> None:
    """Assert the number of resolved cli_args."""
    resolved = context.type_inherit_resolved  # type: ignore[attr-defined]
    actual = len(resolved.get("cli_args", []))
    assert actual == count, f"Expected {count} cli_args, got {actual}"


@then('the type-inherit resolved child_types are "{expected_csv}"')
def step_resolved_child_types(context: Any, expected_csv: str) -> None:
    """Assert the resolved child_types list."""
    resolved = context.type_inherit_resolved  # type: ignore[attr-defined]
    actual = resolved.get("child_types", [])
    expected = _names_from_csv(expected_csv)
    assert actual == expected, f"Expected child_types {expected}, got {actual}"


@then('the type-inherit resolved parent_types are "{expected_csv}"')
def step_resolved_parent_types(context: Any, expected_csv: str) -> None:
    """Assert the resolved parent_types list."""
    resolved = context.type_inherit_resolved  # type: ignore[attr-defined]
    actual = resolved.get("parent_types", [])
    expected = _names_from_csv(expected_csv)
    assert actual == expected, f"Expected parent_types {expected}, got {actual}"


# ═══════════════════════════════════════════════════════════════
# 5. Polymorphism — GIVEN / WHEN / THEN
# ═══════════════════════════════════════════════════════════════


@when('I check type-inherit is_subtype_of "{child}" and "{ancestor}"')
def step_is_subtype_of(context: Any, child: str, ancestor: str) -> None:
    """Run the is_subtype_of polymorphic check."""
    reg = _ensure_registry(context)
    context.type_inherit_subtype_result = is_subtype_of(child, ancestor, reg)  # type: ignore[attr-defined]


@then("the type-inherit subtype check is true")
def step_subtype_true(context: Any) -> None:
    """Assert is_subtype_of returned True."""
    result = context.type_inherit_subtype_result  # type: ignore[attr-defined]
    assert result is True, f"Expected True, got {result}"


@then("the type-inherit subtype check is false")
def step_subtype_false(context: Any) -> None:
    """Assert is_subtype_of returned False."""
    result = context.type_inherit_subtype_result  # type: ignore[attr-defined]
    assert result is False, f"Expected False, got {result}"


@given('a type-inherit tool "{tool_name}" bound to resource type "{rt}"')
def step_register_tool_bound(context: Any, tool_name: str, rt: str) -> None:
    """Register a tool that declares a resource binding."""
    tool_reg = _ensure_tool_registry(context)
    spec = ToolSpec(
        name=tool_name,
        description=f"Tool bound to {rt}",
        handler=_NOOP_HANDLER,
        source_metadata={"resource_bindings": [{"resource_type": rt}]},
    )
    tool_reg.register(spec)


@when('I find type-inherit tools for resource type "{rt}"')
def step_find_tools(context: Any, rt: str) -> None:
    """Use ToolRegistry.find_tools_for_resource to match tools."""
    tool_reg = _ensure_tool_registry(context)
    type_reg = _ensure_registry(context)
    context.type_inherit_matched_tools = tool_reg.find_tools_for_resource(rt, type_reg)  # type: ignore[attr-defined]


@then('the type-inherit matched tools include "{tool_name}"')
def step_matched_tools_include(context: Any, tool_name: str) -> None:
    """Assert the matched tools list includes the named tool."""
    matched = context.type_inherit_matched_tools  # type: ignore[attr-defined]
    names = [t.name for t in matched]
    assert tool_name in names, f"Expected {tool_name!r} in {names}"


@then("the type-inherit matched tools list is empty")
def step_matched_tools_empty(context: Any) -> None:
    """Assert no tools were matched."""
    matched = context.type_inherit_matched_tools  # type: ignore[attr-defined]
    assert len(matched) == 0, f"Expected empty, got {[t.name for t in matched]}"


@when('I find type-inherit subtypes of "{ancestor}"')
def step_find_subtypes(context: Any, ancestor: str) -> None:
    """Run find_subtypes for the given ancestor."""
    reg = _ensure_registry(context)
    context.type_inherit_subtypes = find_subtypes(ancestor, reg)  # type: ignore[attr-defined]


@then('the type-inherit subtypes include "{name}"')
def step_subtypes_include(context: Any, name: str) -> None:
    """Assert the subtypes list includes the named type."""
    subtypes = context.type_inherit_subtypes  # type: ignore[attr-defined]
    assert name in subtypes, f"Expected {name!r} in {subtypes}"
