"""Model registry — name → builder.

Importing the architecture modules has side effects (registers each
class with REGISTRY) so callers can do::

    from training.models import get_model
    cls = get_model("cnn")

without knowing which file defines it.
"""
from __future__ import annotations

from typing import Any, Callable

REGISTRY: dict[str, Callable[..., "BaseModel"]] = {}


def register(name: str):
    def decorator(cls):
        if name in REGISTRY:
            raise ValueError(f"model {name!r} already registered")
        REGISTRY[name] = cls
        cls.__model_name__ = name
        return cls
    return decorator


def get_model(name: str):
    if name not in REGISTRY:
        raise KeyError(
            f"model {name!r} not registered; known: {sorted(REGISTRY)}"
        )
    return REGISTRY[name]


# Eager-import the implementations so the registry is populated.
# Order matters only for which "kind" gets imported first — all are listed.
from training.models import gbt              # noqa: F401,E402
from training.models import knn              # noqa: F401,E402
from training.models import knn_semi         # noqa: F401,E402
from training.models import mlp              # noqa: F401,E402
from training.models import cnn              # noqa: F401,E402
from training.models import gru              # noqa: F401,E402
from training.models import lstm             # noqa: F401,E402
from training.models import transformer      # noqa: F401,E402
from training.models import transformer_ssl  # noqa: F401,E402

from training.models._base import BaseModel  # noqa: E402,F401
