"""
Routage réel des modèles par palier IA (spec « Stratégie LLM par abonnement »).

- PLANS expose ai_models_essential / ai_models_premium (gamme officielle).
- Un plan Pro (moteur openrouter) résout toujours un modèle Essentielle,
  jamais un modèle Premium.
- Le défaut admin (ai_tiers.<palier>.default_model) prime sur le défaut du
  plan, sans redéploiement.
"""

import pytest
from pathlib import Path
from fastapi.testclient import TestClient

from models.subscription import (
    DEFAULT_AI_MODELS_ESSENTIAL,
    DEFAULT_AI_MODELS_PREMIUM,
    PLANS,
    PlanType,
)
from routes.translate_routes import (
    _allowed_providers_for_plan,
    _plan_ai_models,
    _resolve_tier_model,
)


@pytest.fixture
def client(monkeypatch, tmp_path: Path):
    """TestClient with JSON auth and rate limiting disabled."""
    import services.auth_service as auth_svc
    from middleware.rate_limiting import RateLimitManager

    monkeypatch.setattr(auth_svc, "USERS_FILE", tmp_path / "users.json")
    monkeypatch.setattr(auth_svc, "USE_DATABASE", False)
    monkeypatch.setattr(auth_svc, "DATABASE_AVAILABLE", False)

    async def _check_request_allow(self, request):
        return True, "ok", "test"

    async def _check_translation_allow(self, request, file_size_mb=0):
        return True, "ok"

    monkeypatch.setattr(RateLimitManager, "check_request", _check_request_allow)
    monkeypatch.setattr(RateLimitManager, "check_translation", _check_translation_allow)

    from main import app

    return TestClient(app, raise_server_exceptions=True)


def _settings(ai_tiers: dict | None = None):
    from routes.admin_routes import SettingsConfig

    # La résolution est clé-consciente : les tests de résolution partent avec
    # une clé OpenRouter disponible (comme un serveur configuré).
    payload = {"openrouter": {"api_key": "sk-or-test"}}
    if ai_tiers is not None:
        payload["ai_tiers"] = ai_tiers
    return SettingsConfig.model_validate(payload)


# ---------------------------------------------------------------------------
# Gamme officielle dans PLANS
# ---------------------------------------------------------------------------
def test_plans_expose_official_model_ranges():
    essential = PLANS[PlanType.PRO]["ai_models_essential"]
    assert essential == [
        "deepseek/deepseek-v4-flash",
        "z-ai/glm-5.3-flash",
        "minimax/minimax-m3",
    ]
    business = PLANS[PlanType.BUSINESS]
    assert business["ai_models_essential"] == essential
    assert business["ai_models_premium"] == [
        "anthropic/claude-sonnet-5",
        "deepseek/deepseek-v4-pro",
        "z-ai/glm-5.3",
    ]


def test_old_single_model_keys_removed():
    assert "ai_model_essential" not in PLANS[PlanType.PRO]
    assert "ai_model_essential" not in PLANS[PlanType.BUSINESS]
    assert "ai_model_premium" not in PLANS[PlanType.BUSINESS]


# ---------------------------------------------------------------------------
# Résolution par palier — renvoie la route complète (provider, model)
# ---------------------------------------------------------------------------
def test_pro_resolves_essential_plan_default():
    assert _resolve_tier_model(_settings(), "pro", premium=False) == (
        ("openrouter", "deepseek/deepseek-v4-flash")
    )


def test_business_resolves_premium_plan_default():
    assert _resolve_tier_model(_settings(), "business", premium=True) == (
        ("openrouter", "anthropic/claude-sonnet-5")
    )


def test_admin_tier_default_overrides_plan_default():
    cfg = _settings(
        {"essential": {"models": [], "default_model": "z-ai/glm-5.3-flash"}}
    )
    assert _resolve_tier_model(cfg, "pro", premium=False) == (
        "openrouter", "z-ai/glm-5.3-flash"
    )


def test_admin_tier_models_first_used_when_default_empty():
    cfg = _settings(
        {
            "essential": {
                "models": ["minimax/minimax-m3", "deepseek/deepseek-v4-flash"],
                "default_model": "",
            }
        }
    )
    assert _resolve_tier_model(cfg, "pro", premium=False) == (
        "openrouter", "minimax/minimax-m3"
    )


def test_pro_never_resolves_premium_model():
    cfg = _settings(
        {
            "essential": {"models": [], "default_model": ""},
            "premium": {"models": [], "default_model": ""},
        }
    )
    for plan_str in ("pro", "PlanType.PRO"):
        provider, model = _resolve_tier_model(cfg, plan_str, premium=False)
        assert provider == "openrouter"
        assert model in DEFAULT_AI_MODELS_ESSENTIAL
        assert model not in DEFAULT_AI_MODELS_PREMIUM


def test_pro_plan_does_not_allow_premium_provider():
    allowed = _allowed_providers_for_plan(PlanType.PRO)
    assert "openrouter" in allowed
    assert "openrouter_premium" not in allowed


def test_plan_fallback_for_plans_without_range():
    # Free/Enterprise n'ont pas de liste : retombée sur la gamme officielle.
    assert _plan_ai_models(PlanType.FREE, premium=False) == DEFAULT_AI_MODELS_ESSENTIAL
    assert _plan_ai_models(PlanType.ENTERPRISE, premium=True) == DEFAULT_AI_MODELS_PREMIUM


# ---------------------------------------------------------------------------
# GET /plans expose les gammes (affichage public)
# ---------------------------------------------------------------------------
def test_get_plans_exposes_model_lists(client):
    r = client.get("/api/v1/auth/plans")
    assert r.status_code == 200
    plans = {p["id"]: p for p in r.json()["data"]["plans"]}
    assert plans["pro"]["ai_models_essential"] == [
        "deepseek/deepseek-v4-flash",
        "z-ai/glm-5.3-flash",
        "minimax/minimax-m3",
    ]
    assert plans["business"]["ai_models_premium"][0] == "anthropic/claude-sonnet-5"
    assert "ai_model_essential" not in plans["pro"]


# ---------------------------------------------------------------------------
# Point de contact : GET /providers/available affiche le modèle (chaîne simple)
# ---------------------------------------------------------------------------
def test_available_providers_model_is_a_string(monkeypatch, tmp_path):
    """``_resolve_tier_model`` renvoie désormais (provider, model) : le champ
    « model » de /providers/available doit rester une chaîne, égale au modèle
    attendu pour les deux paliers (appelé ici avec un utilisateur Business,
    car la liste est filtrée par forfait)."""
    import routes.legacy_routes as legacy_mod
    import routes.admin_routes as admin_routes_mod

    settings = _settings(
        {
            "essential": {"models": [], "default_model": "z-ai/glm-5.3-flash"},
            "premium": {"models": [], "default_model": "anthropic/claude-sonnet-5"},
        }
    )
    # Les deux passerelles sont affichées dès lors qu'elles sont actives côté
    # réglages (indépendamment des variables d'environnement de la machine).
    settings.openrouter.enabled = True
    settings.openrouter_premium.enabled = True
    monkeypatch.setattr(admin_routes_mod, "load_settings", lambda: settings, raising=True)

    from fastapi.testclient import TestClient
    from middleware.rate_limiting import RateLimitManager
    from models.subscription import PlanType

    async def _check_request_allow(self, request):
        return True, "ok", "test"

    async def _check_translation_allow(self, request, file_size_mb=0):
        return True, "ok"

    monkeypatch.setattr(RateLimitManager, "check_request", _check_request_allow)
    monkeypatch.setattr(RateLimitManager, "check_translation", _check_translation_allow)

    import services.auth_service as auth_svc

    monkeypatch.setattr(auth_svc, "USERS_FILE", tmp_path / "users.json")
    monkeypatch.setattr(auth_svc, "USE_DATABASE", False)
    monkeypatch.setattr(auth_svc, "DATABASE_AVAILABLE", False)

    # Utilisateur Business factice (les moteurs Premium sont filtrés par plan).
    business_user = type("U", (), {"plan": PlanType.BUSINESS, "id": "u-biz"})()

    async def _fake_user():
        return business_user

    from main import app

    app.dependency_overrides[legacy_mod.get_authenticated_user] = _fake_user
    try:
        with TestClient(app, raise_server_exceptions=True) as tc:
            r = tc.get("/api/v1/providers/available")
    finally:
        app.dependency_overrides.pop(legacy_mod.get_authenticated_user, None)

    assert r.status_code == 200, r.text
    engines = {e["id"]: e for e in r.json()["providers"]}
    assert isinstance(engines["openrouter"]["model"], str)
    assert engines["openrouter"]["model"] == "z-ai/glm-5.3-flash"
    assert isinstance(engines["openrouter_premium"]["model"], str)
    assert engines["openrouter_premium"]["model"] == "anthropic/claude-sonnet-5"
