"""Hermes provider plugin for auto-model-router.

Requires auto-model-router installed globally via npm so its `serve` binary is
on PATH:

    npm install -g auto-model-router

The plugin spawns `auto-model-router serve` as a subprocess on a fixed port and
registers a ProviderProfile pointing at it, so Hermes routes each turn through
the router's per-turn cost/complexity logic. The router is a Bun process; this
Python plugin manages it as a child process (Hermes plugins may spawn
subprocesses).

Install by copying this directory to
``$HERMES_HOME/plugins/model-providers/auto-model-router/`` (or symlinking it),
then restart Hermes. Override the port with ``AUTO_MODEL_ROUTER_PORT``.
"""

from __future__ import annotations

import os
import shutil
import subprocess
import sys
import time
import urllib.request

from providers import register_provider
from providers.base import ProviderProfile

# Fixed port the standalone router binds. Hermes points at this URL.
PORT = int(os.environ.get("AUTO_MODEL_ROUTER_PORT", "8788"))
# Remote mode: `auto-model-router connect` sets AUTO_MODEL_ROUTER_URL (and the
# key) in $HERMES_HOME/.env; the plugin then points Hermes at that router and
# spawns nothing locally.
REMOTE_URL = os.environ.get("AUTO_MODEL_ROUTER_URL", "").rstrip("/")
BASE_URL = f"{REMOTE_URL}/v1" if REMOTE_URL else f"http://127.0.0.1:{PORT}/v1"

# The router binary, provided by `npm install -g auto-model-router`.
BIN = "auto-model-router"

# The router's config home. Must be SEPARATE from the default (~/.auto-model-router)
# which omp's embedded router shares: both read the same ledger + config there,
# so sharing it would leak omp's routing toasts into this harness (and vice versa)
# and let the two routers fight over conversation state. Use a hermes-owned home.
_ROUTER_HOME = os.environ.get(
    "AUTO_MODEL_ROUTER_HOME",
    os.path.join(
        os.environ.get("HERMES_HOME", os.path.expanduser("~")), "auto-model-router"
    ),
)


def _router_running() -> bool:
    try:
        with urllib.request.urlopen(
            f"http://127.0.0.1:{PORT}/health", timeout=1
        ) as resp:
            return resp.status == 200
    except Exception:
        return False


def _spawn_router() -> None:
    """Start the standalone router if it is not already running."""
    if _router_running():
        return
    if shutil.which(BIN) is None:
        raise RuntimeError(
            "auto-model-router is not installed or not on PATH. "
            "Run `npm install -g auto-model-router` first."
        )
    env = {**os.environ, "AUTO_MODEL_ROUTER_HOME": _ROUTER_HOME}
    if sys.platform.startswith("win"):
        # npm installs a `.cmd` shim that cannot be exec'd as a bare argv
        # list; shell=True resolves it through the command shell.
        subprocess.Popen(
            f'"{BIN}" serve --port {PORT}',
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            shell=True,
            start_new_session=True,
            env=env,
        )
    else:
        subprocess.Popen(
            [BIN, "serve", "--port", str(PORT)],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            start_new_session=True,
            env=env,
        )
    # Wait for it to come up (bounded).
    for _ in range(50):
        if _router_running():
            return
        time.sleep(0.2)
    raise RuntimeError(f"auto-model-router did not come up on port {PORT}")


if not REMOTE_URL:
    _spawn_router()
profile = ProviderProfile(
    name="auto-model-router",
    api_mode="chat_completions",
    base_url=BASE_URL,
    auth_type="api_key",
    env_vars=("AUTO_MODEL_ROUTER_API_KEY",),
    fallback_models=("auto", "auto-cheap", "auto-max"),
    display_name="auto-model-router",
    description="Per-turn cost/complexity-aware model routing",
    # The harness id the router records on every row (per-harness budgets and
    # reports). The native plugin adds the per-session headers on top.
    default_headers={"X-Omp-Harness": os.environ.get("OMP_HARNESS_ID", "hermes")},
)
register_provider(profile)
