"""Shared helpers for the M5 Robot E2E verification commands."""

from __future__ import annotations

import sys
from pathlib import Path
from typing import Any, NoReturn, cast

from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker

from cleveragents.application.services.resource_registry_service import (
    ResourceRegistryService,
)
from cleveragents.domain.models.core.project import (
    NamespacedProject,
    parse_namespaced_name,
)
from cleveragents.infrastructure.database.models import Base
from cleveragents.infrastructure.database.repositories import (
    NamespacedProjectRepository,
    ProjectResourceLinkRepository,
)


def _fail(msg: str) -> NoReturn:
    """Print failure message to stderr and exit with code 1."""
    print(f"FAIL: {msg}", file=sys.stderr)
    raise SystemExit(1)


class _NoClose:
    """Session wrapper that suppresses ``close()`` for in-memory SQLite."""

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

    def close(self) -> None:
        pass

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


def _setup_db() -> tuple[
    NamespacedProjectRepository,
    ProjectResourceLinkRepository,
    ResourceRegistryService,
    Any,
]:
    """Create an in-memory SQLite DB with all tables."""
    engine = create_engine("sqlite:///:memory:", echo=False)
    Base.metadata.create_all(engine)
    session = sessionmaker(bind=engine, expire_on_commit=False)()
    wrapper = _NoClose(session)

    def factory() -> Session:
        return cast(Session, wrapper)

    proj_repo = NamespacedProjectRepository(session_factory=factory)
    link_repo = ProjectResourceLinkRepository(session_factory=factory)
    svc = ResourceRegistryService(session_factory=factory)
    svc.bootstrap_builtin_types()
    return proj_repo, link_repo, svc, factory


def _create_project(
    repo: NamespacedProjectRepository,
    name: str,
    description: str | None = None,
) -> NamespacedProject:
    """Create and return a NamespacedProject via the repository."""
    parsed = parse_namespaced_name(name)
    proj = NamespacedProject(
        name=parsed.name,
        namespace=parsed.namespace,
        description=description,
    )
    repo.create(proj)
    return repo.get(proj.namespaced_name)


def _create_large_python_repo(root: Path) -> int:
    """Populate *root* with 10,000 small Python files and return the count."""
    file_count = 0
    for i in range(100):
        module_dir = root / f"module_{i:03d}"
        module_dir.mkdir(parents=True, exist_ok=True)
        for j in range(100):
            (module_dir / f"file_{j:03d}.py").write_text(
                f"def f_{i}_{j}():\n    return {i + j}\n"
            )
            file_count += 1
    return file_count
