"""Runtime regression tests for edge app factory."""

from __future__ import annotations

import sys
import types

import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient

from sage.edge.app import create_app


@pytest.fixture
def mock_gateway_module(monkeypatch: pytest.MonkeyPatch) -> FastAPI:
    """Provide a mock gateway module at ``sage.llm.gateway.server``."""
    app = FastAPI(title="Mock Gateway")

    @app.get("/v1/models")
    async def list_models() -> dict[str, list[str]]:
        return {"data": ["mock-model"]}

    module = types.ModuleType("sage.llm.gateway.server")
    module.app = app
    monkeypatch.setitem(sys.modules, "sage.llm.gateway.server", module)
    return app


def test_create_app_no_llm_health_and_ready() -> None:
    """No-LLM mode still exposes edge health/readiness endpoints."""
    app = create_app(mount_llm=False)
    client = TestClient(app)

    health = client.get("/healthz")
    assert health.status_code == 200
    assert health.json() == {
        "status": "ok",
        "service": "SAGE Edge",
        "llm_mounted": False,
        "llm_prefix": "/",
    }

    ready = client.get("/readyz")
    assert ready.status_code == 200
    assert ready.json()["status"] == "ready"


def test_create_app_mount_llm_at_root(mock_gateway_module: FastAPI) -> None:
    """Root mount preserves gateway path and edge health endpoints."""
    app = create_app(mount_llm=True, llm_prefix=None, llm_app=mock_gateway_module)
    client = TestClient(app)

    models = client.get("/v1/models")
    assert models.status_code == 200
    assert models.json() == {"data": ["mock-model"]}

    health = client.get("/healthz")
    assert health.status_code == 200
    assert health.json()["llm_mounted"] is True
    assert health.json()["llm_prefix"] == "/"


def test_create_app_mount_llm_at_custom_prefix(mock_gateway_module: FastAPI) -> None:
    """Custom prefix mount keeps edge health at root and gateway under prefix."""
    app = create_app(mount_llm=True, llm_prefix="/llm", llm_app=mock_gateway_module)
    client = TestClient(app)

    models = client.get("/llm/v1/models")
    assert models.status_code == 200
    assert models.json() == {"data": ["mock-model"]}

    health = client.get("/healthz")
    assert health.status_code == 200
    assert health.json()["llm_mounted"] is True
    assert health.json()["llm_prefix"] == "/llm"


def test_create_app_trailing_slash_prefix_is_normalized(mock_gateway_module: FastAPI) -> None:
    """Trailing slash in custom prefix is normalized deterministically."""
    app = create_app(mount_llm=True, llm_prefix="/llm/", llm_app=mock_gateway_module)
    client = TestClient(app)

    models = client.get("/llm/v1/models")
    assert models.status_code == 200


def test_create_app_invalid_prefix_raises() -> None:
    """Invalid llm prefix must fail fast with explicit error."""
    with pytest.raises(ValueError, match="llm_prefix must start with '/'"):
        create_app(mount_llm=True, llm_prefix="llm", llm_app=FastAPI())


def test_create_app_missing_llm_app_raises() -> None:
    """mount_llm requires explicit llm_app injection."""
    with pytest.raises(RuntimeError, match="requires explicit llm_app injection"):
        create_app(mount_llm=True)
