"""Runnable entrypoint: serve the memory provider as an ASGI app.

For the live negotiation smoke against a Worldtree instance. Config from env:
- RATATOSKR_HEIMDALL_KEY (required): HS256 shared key for the consumer, utf-8.
- RATATOSKR_MEMORY_EMBEDDING_DIM (required): the pinned embedder dim; the
  sqlite-vec index is created at this fixed dim, so a wrong value silently
  breaks search — no default.
- RATATOSKR_MEMORY_DB (default "memory.db"): SQLite path; ":memory:" = ephemeral.
- RATATOSKR_CONSUMER_ID (default "ratatoskr").
- RATATOSKR_PROVIDER_HOST (default "0.0.0.0"),
  RATATOSKR_MEMORY_PROVIDER_PORT (default 8391 — distinct from affect's 8390 so
  both planes can run side-by-side as separate apps, per the v1 contract).
"""
from __future__ import annotations

import os
from collections.abc import Mapping

from ratatoskr.provider.memory_store import build_memory_provider_app, open_memory_store
from ratatoskr.provider.opfeed import maybe_instrument_from_env


def build_memory_app_from_env(env: Mapping[str, str] | None = None):
    """Build the memory ASGI app from environment config (testable seam)."""
    env = os.environ if env is None else env
    key = env.get("RATATOSKR_HEIMDALL_KEY")
    if not key:
        raise RuntimeError(
            "RATATOSKR_HEIMDALL_KEY is required to serve the memory provider"
        )
    raw_dim = env.get("RATATOSKR_MEMORY_EMBEDDING_DIM")
    if not raw_dim:
        raise RuntimeError(
            "RATATOSKR_MEMORY_EMBEDDING_DIM is required (Worldtree's PINNED_EMBEDDER_DIM)"
        )
    try:
        embedding_dim = int(raw_dim)
    except ValueError as exc:
        raise RuntimeError(
            f"RATATOSKR_MEMORY_EMBEDDING_DIM must be an int, got {raw_dim!r}"
        ) from exc
    if embedding_dim <= 0:
        raise RuntimeError("RATATOSKR_MEMORY_EMBEDDING_DIM must be a positive int")
    store = open_memory_store(
        env.get("RATATOSKR_MEMORY_DB", "memory.db"), embedding_dim=embedding_dim
    )
    app = build_memory_provider_app(
        store,
        heimdall_key=key.encode(),
        consumer_id=env.get("RATATOSKR_CONSUMER_ID", "ratatoskr"),
    )
    # Issue #17 (Observe): opt-in dispatch-layer op-feed when RATATOSKR_OPFEED_PATH set.
    return maybe_instrument_from_env(app, env, plane="memory")


def main() -> None:
    import uvicorn

    uvicorn.run(
        build_memory_app_from_env(),
        host=os.environ.get("RATATOSKR_PROVIDER_HOST", "0.0.0.0"),
        port=int(os.environ.get("RATATOSKR_MEMORY_PROVIDER_PORT", "8391")),
    )
