"""Step definitions for resource_type_model_coverage.feature.

These steps target specific uncovered lines in resource_type.py:
- Lines 325-326: validate_inherits rejects invalid name formats
- Line 360: validate_capabilities fills missing keys with defaults
- Lines 368-370: validate_capabilities rejects non-boolean values
- Lines 397-398: virtual type equivalence missing 'criteria' key
- Lines 419-420: virtual type must not be user_addable
- Lines 424-425: virtual type must have sandbox_strategy 'none'
- Lines 429-430: virtual type must not have a handler
- Lines 437-438: virtual type must have all capabilities false
- Line 444: self-inheritance is rejected
- Lines 447-448: built-in cannot inherit from custom type
- Line 537: as_cli_dict includes inherits key
"""

from behave import given, then, when
from pydantic import ValidationError

from cleveragents.domain.models.core.resource_type import (
    ResourceKind,
    ResourceTypeSpec,
    SandboxStrategy,
)

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


def _make_physical_spec(**overrides):
    """Build a minimal valid physical ResourceTypeSpec as keyword dict.

    Uses a namespaced custom name so ``built_in=False`` is fine.
    """
    defaults = dict(
        name="myorg/my-type",
        resource_kind=ResourceKind.PHYSICAL,
        sandbox_strategy=SandboxStrategy.GIT_WORKTREE,
        built_in=False,
    )
    defaults.update(overrides)
    return defaults


def _make_virtual_spec(**overrides):
    """Build a minimal *valid* virtual ResourceTypeSpec as keyword dict.

    Defaults satisfy every virtual-type constraint so tests can override
    exactly one field at a time.
    """
    defaults = dict(
        name="branch",
        resource_kind=ResourceKind.VIRTUAL,
        sandbox_strategy=SandboxStrategy.NONE,
        user_addable=False,
        handler=None,
        equivalence={"criteria": ["ref"]},
        capabilities={
            "read": False,
            "write": False,
            "sandbox": False,
            "checkpoint": False,
        },
        built_in=True,
    )
    defaults.update(overrides)
    return defaults


# ---------------------------------------------------------------------------
# Background
# ---------------------------------------------------------------------------


@given("the resource type model module is imported")
def step_module_imported(context):
    assert ResourceTypeSpec is not None
    assert ResourceKind is not None
    assert SandboxStrategy is not None


# ---------------------------------------------------------------------------
# validate_inherits: invalid format (lines 325-326)
# ---------------------------------------------------------------------------


@when("I create a resource type spec with inherits set to an invalid name")
def step_create_with_invalid_inherits(context):
    try:
        ResourceTypeSpec(**_make_physical_spec(inherits="!!!bad-name"))
        context.rt_error = None
    except ValidationError as exc:
        context.rt_error = exc


@then("a validation error should be raised mentioning invalid inherits type name")
def step_verify_invalid_inherits_error(context):
    assert context.rt_error is not None, "Expected a ValidationError"
    assert "Invalid inherits type name" in str(context.rt_error)


# ---------------------------------------------------------------------------
# validate_capabilities: fill missing keys (line 360)
# ---------------------------------------------------------------------------


@when("I create a resource type spec with capabilities missing some keys")
def step_create_with_partial_capabilities(context):
    # Only provide 'read'; write, sandbox, checkpoint should be auto-filled
    context.rt_spec = ResourceTypeSpec(
        **_make_physical_spec(capabilities={"read": True})
    )


@then("the resulting capabilities should contain all expected keys with defaults")
def step_verify_capabilities_defaults(context):
    caps = context.rt_spec.capabilities
    assert "read" in caps and caps["read"] is True
    assert "write" in caps and caps["write"] is True  # default for non-checkpoint
    assert "sandbox" in caps and caps["sandbox"] is True
    assert (
        "checkpoint" in caps and caps["checkpoint"] is False
    )  # default for checkpoint


# ---------------------------------------------------------------------------
# validate_capabilities: non-boolean value (lines 368-370)
# ---------------------------------------------------------------------------


@when("I create a resource type spec with a non-boolean capability value")
def step_create_with_nonbool_capability(context):
    # Pydantic's dict[str, bool] annotation coerces values before the
    # field_validator runs. To exercise the isinstance check on lines 368-370
    # we call the validator classmethod directly with a non-bool value.
    try:
        ResourceTypeSpec.validate_capabilities(
            {
                "read": 42,  # not a bool — triggers lines 368-370
                "write": True,
                "sandbox": True,
                "checkpoint": False,
            }
        )
        context.rt_error = None
    except ValueError as exc:
        context.rt_error = exc


@then("a validation error should be raised mentioning capability must be a boolean")
def step_verify_nonbool_capability_error(context):
    assert context.rt_error is not None, "Expected a ValueError"
    assert "must be a boolean" in str(context.rt_error)


# ---------------------------------------------------------------------------
# virtual type: equivalence missing criteria (lines 397-398)
# ---------------------------------------------------------------------------


@when("I create a virtual resource type with equivalence missing the criteria key")
def step_create_virtual_no_criteria(context):
    try:
        ResourceTypeSpec(**_make_virtual_spec(equivalence={"strategy": "hash"}))
        context.rt_error = None
    except ValidationError as exc:
        context.rt_error = exc


@then(
    "a validation error should be raised mentioning equivalence must contain criteria"
)
def step_verify_missing_criteria_error(context):
    assert context.rt_error is not None, "Expected a ValidationError"
    assert "criteria" in str(context.rt_error)


# ---------------------------------------------------------------------------
# virtual type: user_addable (lines 419-420)
# ---------------------------------------------------------------------------


@when("I create a virtual resource type that is user addable")
def step_create_virtual_user_addable(context):
    try:
        ResourceTypeSpec(**_make_virtual_spec(user_addable=True))
        context.rt_error = None
    except ValidationError as exc:
        context.rt_error = exc


@then("a validation error should be raised mentioning virtual must not be user addable")
def step_verify_user_addable_error(context):
    assert context.rt_error is not None, "Expected a ValidationError"
    assert "must not be user_addable" in str(context.rt_error)


# ---------------------------------------------------------------------------
# virtual type: sandbox strategy != none (lines 424-425)
# ---------------------------------------------------------------------------


@when("I create a virtual resource type with a non-none sandbox strategy")
def step_create_virtual_bad_sandbox(context):
    try:
        ResourceTypeSpec(
            **_make_virtual_spec(sandbox_strategy=SandboxStrategy.GIT_WORKTREE)
        )
        context.rt_error = None
    except ValidationError as exc:
        context.rt_error = exc


@then(
    "a validation error should be raised mentioning virtual must have sandbox strategy none"
)
def step_verify_sandbox_error(context):
    assert context.rt_error is not None, "Expected a ValidationError"
    assert "sandbox_strategy" in str(context.rt_error)


# ---------------------------------------------------------------------------
# virtual type: handler set (lines 429-430)
# ---------------------------------------------------------------------------


@when("I create a virtual resource type with a handler set")
def step_create_virtual_with_handler(context):
    try:
        ResourceTypeSpec(**_make_virtual_spec(handler="some.module:Handler"))
        context.rt_error = None
    except ValidationError as exc:
        context.rt_error = exc


@then("a validation error should be raised mentioning virtual must not have a handler")
def step_verify_handler_error(context):
    assert context.rt_error is not None, "Expected a ValidationError"
    assert "must not have a handler" in str(context.rt_error)


# ---------------------------------------------------------------------------
# virtual type: capabilities not all false (lines 437-438)
# ---------------------------------------------------------------------------


@when("I create a virtual resource type with a true capability")
def step_create_virtual_true_caps(context):
    try:
        ResourceTypeSpec(
            **_make_virtual_spec(
                capabilities={
                    "read": True,
                    "write": False,
                    "sandbox": False,
                    "checkpoint": False,
                }
            )
        )
        context.rt_error = None
    except ValidationError as exc:
        context.rt_error = exc


@then(
    "a validation error should be raised mentioning virtual must have all capabilities false"
)
def step_verify_capabilities_false_error(context):
    assert context.rt_error is not None, "Expected a ValidationError"
    assert "all capabilities set to false" in str(context.rt_error)


# ---------------------------------------------------------------------------
# self-inheritance (line 444)
# ---------------------------------------------------------------------------


@when("I create a resource type spec that inherits from itself")
def step_create_self_inheriting(context):
    try:
        ResourceTypeSpec(**_make_physical_spec(inherits="myorg/my-type"))
        context.rt_error = None
    except ValidationError as exc:
        context.rt_error = exc


@then("a validation error should be raised mentioning cannot inherit from itself")
def step_verify_self_inherit_error(context):
    assert context.rt_error is not None, "Expected a ValidationError"
    assert "cannot inherit from itself" in str(context.rt_error)


# ---------------------------------------------------------------------------
# built-in inherits from custom (lines 447-448)
# ---------------------------------------------------------------------------


@when("I create a built-in resource type that inherits from a custom type")
def step_create_builtin_inherits_custom(context):
    try:
        ResourceTypeSpec(
            **_make_physical_spec(
                name="git-checkout",
                built_in=True,
                inherits="custom/parent-type",
            )
        )
        context.rt_error = None
    except ValidationError as exc:
        context.rt_error = exc


@then(
    "a validation error should be raised mentioning built-in cannot inherit from custom"
)
def step_verify_builtin_inherits_custom_error(context):
    assert context.rt_error is not None, "Expected a ValidationError"
    assert "cannot inherit from custom" in str(context.rt_error)


# ---------------------------------------------------------------------------
# as_cli_dict includes inherits (line 537)
# ---------------------------------------------------------------------------


@given("a valid physical resource type spec with inherits set")
def step_create_spec_with_inherits(context):
    context.rt_spec = ResourceTypeSpec(
        **_make_physical_spec(inherits="myorg/parent-type")
    )


@when("I call as_cli_dict on the spec")
def step_call_as_cli_dict(context):
    context.rt_cli_dict = context.rt_spec.as_cli_dict()


@then("the resulting dict should contain the inherits key")
def step_verify_inherits_in_cli_dict(context):
    assert "inherits" in context.rt_cli_dict
    assert context.rt_cli_dict["inherits"] == "myorg/parent-type"
