"""Step definitions for ResourceTypeSpec inheritance cycle detection.

Tests that the validation detects multi-level inheritance cycles,
not just direct self-inheritance.
"""

from __future__ import annotations

from typing import Any

from behave import given, then, when

from cleveragents.domain.models.core._resource_type_validation import (
    MAX_INHERITANCE_DEPTH,
)
from cleveragents.domain.models.core.resource_type import (
    ResourceTypeSpec,
)


@given("a resource type registry for cycle detection")
def step_init_registry(context: Any) -> None:
    """Initialize an empty registry for cycle detection tests."""
    context.type_registry = {}  # type: ignore[attr-defined]
    context.creation_error = None  # type: ignore[attr-defined]


@given('a registered type "{name}" inheriting from "{parent}"')
def step_register_type(context: Any, name: str, parent: str) -> None:
    """Register a type in the test registry."""
    registry = context.type_registry  # type: ignore[attr-defined]
    registry[name] = {
        "name": name,
        "resource_kind": "physical",
        "sandbox_strategy": "none",
        "inherits": parent,
    }


@when('I create a ResourceTypeSpec with name "{name}" inheriting "{parent}"')
def step_create_with_inherits(context: Any, name: str, parent: str) -> None:
    """Attempt to create a ResourceTypeSpec with the given inheritance.

    Passes the test registry as Pydantic validation context so that
    ResourceTypeSpec._validate_model() performs multi-level cycle detection
    through the production code path.
    """
    registry: dict[str, Any] = getattr(context, "type_registry", {})
    ctx = {"type_registry": registry} if registry else None
    try:
        spec = ResourceTypeSpec.model_validate(
            {
                "name": name,
                "resource_kind": "physical",
                "sandbox_strategy": "none",
                "inherits": parent,
            },
            context=ctx,
        )
        context.created_spec = spec  # type: ignore[attr-defined]
        context.creation_error = None  # type: ignore[attr-defined]
    except (ValueError, TypeError) as exc:
        context.creation_error = exc  # type: ignore[attr-defined]


@when('I create a ResourceTypeSpec with name "{name}" inheriting nothing')
def step_create_without_inherits(context: Any, name: str) -> None:
    """Attempt to create a ResourceTypeSpec without inheritance."""
    try:
        spec = ResourceTypeSpec.model_validate(
            {
                "name": name,
                "resource_kind": "physical",
                "sandbox_strategy": "none",
                "inherits": None,
            }
        )
        context.created_spec = spec  # type: ignore[attr-defined]
        context.creation_error = None  # type: ignore[attr-defined]
    except (ValueError, TypeError) as exc:
        context.creation_error = exc  # type: ignore[attr-defined]


@then('the creation should fail with "{fragment}"')
def step_creation_failed(context: Any, fragment: str) -> None:
    """Assert that creation failed with an error containing the fragment."""
    err = context.creation_error  # type: ignore[attr-defined]
    assert err is not None, "Expected creation to fail but it succeeded"
    assert fragment.lower() in str(err).lower(), (
        f"Expected error to contain '{fragment}', got: {err}"
    )


@then('the creation should fail with either "{fragment1}" or "{fragment2}"')
def step_creation_failed_either(context: Any, fragment1: str, fragment2: str) -> None:
    """Assert that creation failed with an error containing either fragment."""
    err = context.creation_error  # type: ignore[attr-defined]
    assert err is not None, "Expected creation to fail but it succeeded"
    err_lower = str(err).lower()
    assert fragment1.lower() in err_lower or fragment2.lower() in err_lower, (
        f"Expected error to contain '{fragment1}' or '{fragment2}', got: {err}"
    )


@then("the creation should succeed")
def step_creation_succeeded(context: Any) -> None:
    """Assert that creation succeeded."""
    err = context.creation_error  # type: ignore[attr-defined]
    assert err is None, f"Expected creation to succeed but got error: {err}"
    assert hasattr(context, "created_spec"), "Expected created_spec to be set"


@when("I create a ResourceTypeSpec whose ancestry chain exceeds the depth limit")
def step_create_exceeds_depth(context: Any) -> None:
    """Build a registry chain longer than MAX_INHERITANCE_DEPTH and attempt creation."""
    chain_len = MAX_INHERITANCE_DEPTH + 1
    registry: dict[str, Any] = {
        f"chain/t{i}": {"inherits": f"chain/t{i + 1}"} for i in range(chain_len)
    }
    try:
        spec = ResourceTypeSpec.model_validate(
            {
                "name": "chain/new",
                "resource_kind": "physical",
                "sandbox_strategy": "none",
                "inherits": "chain/t0",
            },
            context={"type_registry": registry},
        )
        context.created_spec = spec  # type: ignore[attr-defined]
        context.creation_error = None  # type: ignore[attr-defined]
    except (ValueError, TypeError) as exc:
        context.creation_error = exc  # type: ignore[attr-defined]
