"""Step definitions for DomainBaseModel shared configuration tests.

Only steps that are NOT already defined in other step modules are defined here.
Steps shared with aimodelscredentials_steps.py, aimodelserrors_steps.py, and
aimodelsproviders_steps.py are reused automatically by Behave's global step
registry.
"""

from behave import then, when
from pydantic import BaseModel

from cleveragents.domain.models.base import DomainBaseModel

# ---------------------------------------------------------------------------
# Shared expected config values
# ---------------------------------------------------------------------------

_EXPECTED_CONFIG: dict[str, object] = {
    "str_strip_whitespace": True,
    "validate_assignment": True,
    "arbitrary_types_allowed": False,
    "populate_by_name": True,
    "use_enum_values": True,
}


# ---------------------------------------------------------------------------
# When — new imports (not defined in existing step files)
# ---------------------------------------------------------------------------


@when("I import DomainBaseModel from the domain models base module")
def step_import_domain_base_model(context: object) -> None:
    """Import DomainBaseModel and store on context."""
    context.domain_base_model_class = DomainBaseModel
    context.imported_class = DomainBaseModel


@when("I inspect the DomainBaseModel model_config")
def step_inspect_domain_base_model_config(context: object) -> None:
    """Store the DomainBaseModel model_config on context."""
    context.inspected_config = DomainBaseModel.model_config


@when("I import ModelError from aimodelserrors")
def step_import_model_error(context: object) -> None:
    """Import ModelError."""
    from cleveragents.domain.models.aimodelserrors.ai_models_errors import ModelError

    context.imported_class = ModelError


@when("I import FallbackResult from aimodelserrors")
def step_import_fallback_result(context: object) -> None:
    """Import FallbackResult."""
    from cleveragents.domain.models.aimodelserrors.ai_models_errors import (
        FallbackResult,
    )

    context.imported_class = FallbackResult


@when("I import ModelProviderExtraAuthVars from aimodelsproviders")
def step_import_model_provider_extra_auth_vars(context: object) -> None:
    """Import ModelProviderExtraAuthVars."""
    from cleveragents.domain.models.aimodelsproviders.ai_models_providers import (
        ModelProviderExtraAuthVars,
    )

    context.imported_class = ModelProviderExtraAuthVars


@when("I import ModelProviderConfigSchema from aimodelsproviders")
def step_import_model_provider_config_schema(context: object) -> None:
    """Import ModelProviderConfigSchema."""
    from cleveragents.domain.models.aimodelsproviders.ai_models_providers import (
        ModelProviderConfigSchema,
    )

    context.imported_class = ModelProviderConfigSchema


@when("I import AuthHeader from auth")
def step_import_auth_header(context: object) -> None:
    """Import AuthHeader."""
    from cleveragents.domain.models.auth.auth import AuthHeader

    context.imported_class = AuthHeader


@when("I import TrialPlansExceededError from auth")
def step_import_trial_plans_exceeded_error(context: object) -> None:
    """Import TrialPlansExceededError."""
    from cleveragents.domain.models.auth.auth import TrialPlansExceededError

    context.imported_class = TrialPlansExceededError


@when("I import TrialMessagesExceededError from auth")
def step_import_trial_messages_exceeded_error(context: object) -> None:
    """Import TrialMessagesExceededError."""
    from cleveragents.domain.models.auth.auth import TrialMessagesExceededError

    context.imported_class = TrialMessagesExceededError


@when("I import BillingError from auth")
def step_import_billing_error(context: object) -> None:
    """Import BillingError."""
    from cleveragents.domain.models.auth.auth import BillingError

    context.imported_class = BillingError


@when("I import ApiError from auth")
def step_import_api_error(context: object) -> None:
    """Import ApiError."""
    from cleveragents.domain.models.auth.auth import ApiError

    context.imported_class = ApiError


@when("I import ClientAccount from auth")
def step_import_client_account(context: object) -> None:
    """Import ClientAccount."""
    from cleveragents.domain.models.auth.auth import ClientAccount

    context.imported_class = ClientAccount


@when("I import ClientAuth from auth")
def step_import_client_auth(context: object) -> None:
    """Import ClientAuth."""
    from cleveragents.domain.models.auth.auth import ClientAuth

    context.imported_class = ClientAuth


@when("I import PlanConfig from planconfig")
def step_import_plan_config(context: object) -> None:
    """Import PlanConfig."""
    from cleveragents.domain.models.planconfig.plan_config import PlanConfig

    context.imported_class = PlanConfig


@when("I import ConfigSetting from planconfig")
def step_import_config_setting(context: object) -> None:
    """Import ConfigSetting."""
    from cleveragents.domain.models.planconfig.plan_config import ConfigSetting

    context.imported_class = ConfigSetting


# When — class definition inspection


@when("I inspect the ModelProviderOption class definition")
def step_inspect_model_provider_option(context: object) -> None:
    """Store ModelProviderOption for inspection."""
    from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
        ModelProviderOption,
    )

    context.inspected_class = ModelProviderOption


@when("I inspect the ModelError class definition")
def step_inspect_model_error(context: object) -> None:
    """Store ModelError for inspection."""
    from cleveragents.domain.models.aimodelserrors.ai_models_errors import ModelError

    context.inspected_class = ModelError


@when("I inspect the ModelProviderConfigSchema class definition")
def step_inspect_model_provider_config_schema_def(context: object) -> None:
    """Store ModelProviderConfigSchema for inspection."""
    from cleveragents.domain.models.aimodelsproviders.ai_models_providers import (
        ModelProviderConfigSchema,
    )

    context.inspected_class = ModelProviderConfigSchema


@when("I inspect the AuthHeader class definition")
def step_inspect_auth_header(context: object) -> None:
    """Store AuthHeader for inspection."""
    from cleveragents.domain.models.auth.auth import AuthHeader

    context.inspected_class = AuthHeader


@when("I inspect the PlanConfig class definition")
def step_inspect_plan_config(context: object) -> None:
    """Store PlanConfig for inspection."""
    from cleveragents.domain.models.planconfig.plan_config import PlanConfig

    context.inspected_class = PlanConfig


# ---------------------------------------------------------------------------
# Then — DomainBaseModel assertions
# ---------------------------------------------------------------------------


@then("the DomainBaseModel class should be available")
def step_domain_base_model_available(context: object) -> None:
    """Verify DomainBaseModel is available."""
    assert context.domain_base_model_class is not None
    assert context.domain_base_model_class.__name__ == "DomainBaseModel"


@then("DomainBaseModel should be a subclass of pydantic BaseModel")
def step_domain_base_model_is_pydantic(context: object) -> None:
    """Verify DomainBaseModel inherits from pydantic BaseModel."""
    assert issubclass(context.domain_base_model_class, BaseModel)


@then("the DomainBaseModel str_strip_whitespace should be True")
def step_domain_base_model_str_strip(context: object) -> None:
    """Verify str_strip_whitespace on DomainBaseModel."""
    assert context.inspected_config.get("str_strip_whitespace") is True


@then("the DomainBaseModel validate_assignment should be True")
def step_domain_base_model_validate_assignment(context: object) -> None:
    """Verify validate_assignment on DomainBaseModel."""
    assert context.inspected_config.get("validate_assignment") is True


@then("the DomainBaseModel arbitrary_types_allowed should be False")
def step_domain_base_model_arbitrary_types(context: object) -> None:
    """Verify arbitrary_types_allowed on DomainBaseModel."""
    assert context.inspected_config.get("arbitrary_types_allowed") is False


@then("the DomainBaseModel populate_by_name should be True")
def step_domain_base_model_populate_by_name(context: object) -> None:
    """Verify populate_by_name on DomainBaseModel."""
    assert context.inspected_config.get("populate_by_name") is True


@then("the DomainBaseModel use_enum_values should be True")
def step_domain_base_model_use_enum_values(context: object) -> None:
    """Verify use_enum_values on DomainBaseModel."""
    assert context.inspected_config.get("use_enum_values") is True


# ---------------------------------------------------------------------------
# Then — subclass assertions (generic, reused for all domain models)
# ---------------------------------------------------------------------------


@then("{class_name} should be a subclass of DomainBaseModel")
def step_is_subclass_of_domain_base_model(context: object, class_name: str) -> None:
    """Verify the imported class is a subclass of DomainBaseModel."""
    assert issubclass(context.imported_class, DomainBaseModel), (
        f"{class_name} is not a subclass of DomainBaseModel"
    )


@then("the {class_name} model_config should match DomainBaseModel")
def step_config_matches_domain_base_model(context: object, class_name: str) -> None:
    """Verify the imported class inherits the expected model_config values."""
    cfg = context.imported_class.model_config
    for key, expected in _EXPECTED_CONFIG.items():
        actual = cfg.get(key)
        assert actual == expected, (
            f"{class_name}.model_config[{key!r}] = {actual!r}, expected {expected!r}"
        )


# ---------------------------------------------------------------------------
# Then — no inline model_config duplication assertions
# ---------------------------------------------------------------------------


@then("{class_name} should not define its own model_config")
def step_no_own_model_config(context: object, class_name: str) -> None:
    """Verify the class source does not contain an inline model_config assignment.

    Pydantic's metaclass copies model_config into every subclass __dict__
    automatically, so we inspect the source code instead of __dict__ to
    confirm no *explicit* duplication exists.
    """
    import inspect

    source = inspect.getsource(context.inspected_class)
    # Remove the class header line so we only look at the class body
    body_lines = source.splitlines()[1:]
    body = "\n".join(body_lines)
    assert "model_config" not in body, (
        f"{class_name} has an explicit model_config in its source — "
        "should inherit from DomainBaseModel without redefinition"
    )
