"""Step definitions for container_mount_flag.feature."""

from __future__ import annotations

import json
from typing import Any

import typer
from behave import given, then, when
from behave.runner import Context
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from cleveragents.application.services.resource_registry_service import (
    ResourceRegistryService,
)
from cleveragents.cli.commands.resource import _parse_mount_spec
from cleveragents.infrastructure.database.models import Base


class _NoClose:
    """Proxy that suppresses ``close()`` on an in-memory SQLite session.

    Without this, SQLAlchemy's ``session.close()`` releases the
    connection, destroying the in-memory database between operations.
    """

    __slots__ = ("_s",)

    def __init__(self, s: object) -> None:
        object.__setattr__(self, "_s", s)

    def close(self) -> None:
        pass

    def __getattr__(self, n: str) -> object:
        return getattr(object.__getattribute__(self, "_s"), n)


@given("a resource registry service for mount_flag")
def step_setup_registry(context: Context) -> None:
    engine = create_engine("sqlite:///:memory:", echo=False)
    Base.metadata.create_all(engine)
    session = sessionmaker(bind=engine, expire_on_commit=False)()
    wrapper = _NoClose(session)
    svc = ResourceRegistryService(session_factory=lambda: wrapper)
    svc.bootstrap_builtin_types()
    context.mf_service = svc


@when('I add a container-instance with mount "{spec}" for mount_flag')
def step_add_with_mount(context: Context, spec: str) -> None:
    mount_data = _parse_mount_spec(spec)
    properties: dict[str, Any] = {
        "image": "ubuntu:latest",
        "mounts": json.dumps([mount_data]),
    }
    res = context.mf_service.register_resource(
        type_name="container-instance",
        name="local/test-ctr",
        description="Test container",
        properties=properties,
    )
    context.mf_resource = res
    context.mf_mounts = [mount_data]


@when("I add a container-instance with mounts for mount_flag:")
def step_add_with_dual_mounts(context: Context) -> None:
    mounts = [_parse_mount_spec(row["mount_spec"]) for row in context.table]
    properties: dict[str, Any] = {
        "image": "node:18",
        "mounts": json.dumps(mounts),
    }
    res = context.mf_service.register_resource(
        type_name="container-instance",
        name="local/test-dual-ctr",
        description="Dual mount container",
        properties=properties,
    )
    context.mf_resource = res
    context.mf_mounts = mounts


@when("I show the mount_flag resource")
def step_show_resource(context: Context) -> None:
    res = context.mf_service.show_resource(context.mf_resource.name)
    context.mf_show_output = str(res.properties)


@when('I parse mount spec "{spec}" for mount_flag')
def step_parse_mount(context: Context, spec: str) -> None:
    try:
        context.mf_parsed = _parse_mount_spec(spec)
        context.mf_parse_error = None
    except (typer.BadParameter, ValueError) as exc:
        context.mf_parsed = None
        context.mf_parse_error = exc


@then("the mount_flag resource should have {count:d} mount")
def step_check_mount_count_singular(context: Context, count: int) -> None:
    assert len(context.mf_mounts) == count


@then("the mount_flag resource should have {count:d} mounts")
def step_check_mount_count_plural(context: Context, count: int) -> None:
    assert len(context.mf_mounts) == count


@then('mount_flag mount {idx:d} source should be "{val}"')
def step_check_mount_source(context: Context, idx: int, val: str) -> None:
    assert context.mf_mounts[idx]["source"] == val


@then('mount_flag mount {idx:d} target should be "{val}"')
def step_check_mount_target(context: Context, idx: int, val: str) -> None:
    assert context.mf_mounts[idx]["target"] == val


@then('mount_flag mount {idx:d} mode should be "{val}"')
def step_check_mount_mode(context: Context, idx: int, val: str) -> None:
    assert context.mf_mounts[idx]["mode"] == val


@then('mount_flag mount {idx:d} type should be "{val}"')
def step_check_mount_type(context: Context, idx: int, val: str) -> None:
    assert context.mf_mounts[idx]["type"] == val


@then('the mount_flag show output should contain "{text}"')
def step_show_contains(context: Context, text: str) -> None:
    assert text in context.mf_show_output, (
        f"'{text}' not in show output: {context.mf_show_output}"
    )


@then('mount_flag parse should fail with "{message}"')
def step_parse_should_fail(context: Context, message: str) -> None:
    assert context.mf_parse_error is not None, "Expected parse error"
    assert message.lower() in str(context.mf_parse_error).lower()


@when('I parse mount spec "{spec}" for mount_flag on type "{type_name}"')
def step_parse_wrong_type(context: Context, spec: str, type_name: str) -> None:
    """Simulate --mount on a non-container type."""
    context.mf_wrong_type = type_name
    context.mf_wrong_type_spec = spec


@then("mount_flag type validation should fail")
def step_type_validation_fail(context: Context) -> None:
    assert context.mf_wrong_type != "container-instance", "Expected non-container type"
