from __future__ import annotations

import json
from pathlib import Path

import pytest

from model_catalog import FALLBACK_EFFORTS, ModelCatalog


def write_catalog(tmp_path: Path, models: list[dict]) -> Path:
    path = tmp_path / "models_cache.json"
    path.write_text(json.dumps({"models": models}), encoding="utf-8")
    return path


def test_reads_slugs_efforts_and_default(tmp_path: Path) -> None:
    path = write_catalog(
        tmp_path,
        [
            {
                "slug": "gpt-test",
                "default_reasoning_level": "medium",
                "supported_reasoning_levels": [{"effort": "low"}, {"effort": "medium"}],
            }
        ],
    )
    catalog = ModelCatalog(path)
    assert catalog.known("gpt-test")
    assert catalog.models() == ("gpt-test",)
    assert catalog.supported_efforts("gpt-test") == ("low", "medium")
    assert catalog.default_effort("gpt-test") == "medium"


def test_default_falls_back_to_first_supported_when_absent(tmp_path: Path) -> None:
    path = write_catalog(
        tmp_path,
        [{"slug": "gpt-test", "supported_reasoning_levels": [{"effort": "high"}]}],
    )
    assert ModelCatalog(path).default_effort("gpt-test") == "high"


def test_pro_resolves_to_highest_supported_tier(tmp_path: Path) -> None:
    path = write_catalog(
        tmp_path,
        [
            {"slug": "with-ultra", "supported_reasoning_levels": [{"effort": "max"}, {"effort": "ultra"}]},
            {"slug": "no-ultra", "supported_reasoning_levels": [{"effort": "high"}, {"effort": "max"}]},
        ],
    )
    catalog = ModelCatalog(path)
    assert catalog.resolve_effort("with-ultra", "pro") == "ultra"
    assert catalog.resolve_effort("no-ultra", "pro") == "max"


def test_med_alias_canonicalizes(tmp_path: Path) -> None:
    path = write_catalog(
        tmp_path, [{"slug": "gpt-test", "supported_reasoning_levels": [{"effort": "medium"}]}]
    )
    assert ModelCatalog(path).resolve_effort("gpt-test", "med") == "medium"


def test_unsupported_effort_names_what_fits(tmp_path: Path) -> None:
    path = write_catalog(
        tmp_path, [{"slug": "gpt-test", "supported_reasoning_levels": [{"effort": "low"}]}]
    )
    with pytest.raises(ValueError, match="supported: low"):
        ModelCatalog(path).resolve_effort("gpt-test", "xhigh")


def test_unknown_model_rejected(tmp_path: Path) -> None:
    path = write_catalog(
        tmp_path, [{"slug": "gpt-test", "supported_reasoning_levels": [{"effort": "low"}]}]
    )
    catalog = ModelCatalog(path)
    assert not catalog.known("absent")
    with pytest.raises(ValueError, match="unknown model 'absent'"):
        catalog.resolve_effort("absent", "low")


@pytest.mark.parametrize(
    "content", ["", "not json", json.dumps({"models": []}), json.dumps({"models": [{"slug": "x"}]})]
)
def test_unusable_catalog_uses_fallback(tmp_path: Path, content: str) -> None:
    path = tmp_path / "models_cache.json"
    path.write_text(content, encoding="utf-8")
    assert ModelCatalog(path).models() == tuple(sorted(FALLBACK_EFFORTS))


def test_missing_catalog_uses_fallback(tmp_path: Path) -> None:
    assert ModelCatalog(tmp_path / "absent.json").models() == tuple(sorted(FALLBACK_EFFORTS))
