"""Unit tests for the access-tier configuration system (Wave 5)."""

from __future__ import annotations

import pytest

from vastian.access_tiers import (
    BOARD_PREFIXES,
    VALID_TIERS,
    get_board_prefix,
    get_model_id,
    get_model_tier_for_agent,
    get_scenario_domains,
    get_scenario_template,
    is_agent_enabled,
    is_feature_allowed,
    reload_config,
    tier_summary,
    visible_boards,
)


class TestAccessTierConfig:
    """Verify the YAML config loads and returns expected structure."""

    def test_reload_returns_dict(self) -> None:
        cfg = reload_config()
        assert isinstance(cfg, dict)
        assert "models" in cfg
        assert "tiers" in cfg

    def test_all_tiers_present(self) -> None:
        cfg = reload_config()
        for tier in VALID_TIERS:
            assert tier in cfg["tiers"], f"Missing tier: {tier}"

    def test_model_tiers_defined(self) -> None:
        cfg = reload_config()
        for model_tier in ("cheap", "mid", "premium"):
            assert model_tier in cfg["models"]
            assert "openai" in cfg["models"][model_tier]
            assert "anthropic" in cfg["models"][model_tier]


class TestFeatureGating:
    """Test is_feature_allowed across tiers."""

    def test_open_has_manual_backup(self) -> None:
        assert is_feature_allowed("manual_backup", "open")

    def test_open_has_councils_basic(self) -> None:
        assert is_feature_allowed("councils_basic", "open")

    def test_open_has_no_full_councils(self) -> None:
        assert not is_feature_allowed("councils", "open")

    def test_standard_has_councils(self) -> None:
        assert is_feature_allowed("councils", "standard")

    def test_admin_has_everything(self) -> None:
        # admin has "all" in features list
        assert is_feature_allowed("manual_backup", "admin")
        assert is_feature_allowed("councils", "admin")
        assert is_feature_allowed("scheduled", "admin")
        assert is_feature_allowed("any_random_feature", "admin")

    def test_elevated_has_scheduled(self) -> None:
        assert is_feature_allowed("scheduled", "elevated")

    def test_standard_no_scheduled(self) -> None:
        assert not is_feature_allowed("scheduled", "standard")

    def test_unknown_tier_falls_back_to_open(self) -> None:
        # Unknown tier should fall back to open
        assert is_feature_allowed("manual_backup", "nonexistent_tier")
        assert not is_feature_allowed("councils", "nonexistent_tier")


class TestBoardVisibility:
    """Test visible_boards per tier."""

    def test_open_sees_boards(self) -> None:
        boards = visible_boards("open")
        assert "user" in boards

    def test_standard_sees_all_boards(self) -> None:
        boards = visible_boards("standard")
        assert {"user", "comms", "company", "agent"}.issubset(set(boards))

    def test_elevated_sees_all_boards(self) -> None:
        boards = visible_boards("elevated")
        assert {"user", "comms", "company", "agent"}.issubset(set(boards))

    def test_admin_sees_all_boards(self) -> None:
        boards = visible_boards("admin")
        assert {"user", "comms", "company", "agent", "ops"}.issubset(set(boards))


class TestAgentEnablement:
    """Test is_agent_enabled — all agents enabled at all tiers (agent_disabled: [])."""

    def test_all_enabled_at_open(self) -> None:
        for agent in (
            "charles",
            "henry",
            "dominic",
            "victor",
            "adrian",
            "noah",
            "liam",
            "finley",
            "theo",
            "elias",
            "concord",
            "jake",
            "orion",
            "rowan",
            "felix",
            "arjuna",
            "kiran",
            "maria",
            "maya",
            "sage",
        ):
            assert is_agent_enabled(agent, "open"), f"{agent} should be enabled at open"

    def test_all_enabled_at_standard(self) -> None:
        for agent in ("henry", "dominic", "victor", "adrian", "noah", "charles"):
            assert is_agent_enabled(agent, "standard"), f"{agent} should be enabled at standard"

    def test_all_enabled_at_admin(self) -> None:
        for agent in ("henry", "dominic", "victor", "adrian", "noah"):
            assert is_agent_enabled(agent, "admin")


class TestModelTierMapping:
    """Test get_model_tier_for_agent and get_model_id."""

    def test_open_default_mid(self) -> None:
        # open default_model is mid, not cheap
        tier = get_model_tier_for_agent("charles", "open")
        assert tier in ("cheap", "mid")

    def test_standard_default_mid(self) -> None:
        # standard default_model is mid
        tier = get_model_tier_for_agent("theo", "standard")
        assert tier in ("cheap", "mid")

    def test_standard_henry_premium(self) -> None:
        # henry at standard: config may assign cheap/mid/premium
        tier = get_model_tier_for_agent("henry", "standard")
        assert tier in ("cheap", "mid", "premium")

    def test_admin_default_premium(self) -> None:
        # admin default_model is premium
        tier = get_model_tier_for_agent("henry", "admin")
        assert tier in ("cheap", "mid", "premium")

    def test_unknown_agent_gets_default(self) -> None:
        # Agent not listed should get default_model for the tier
        tier = get_model_tier_for_agent("nonexistent_agent", "standard")
        assert tier == "mid"  # standard default_model

    def test_get_model_id_openai_cheap(self) -> None:
        model = get_model_id("felix", "open", "openai")
        assert model in ("gpt-4o-mini", "gpt-4o")

    def test_get_model_id_anthropic_premium(self) -> None:
        # henry at admin uses model from get_model_tier_for_agent
        model = get_model_id("henry", "admin", "anthropic")
        assert model in ("claude-opus-4-5-20251101", "claude-sonnet-4-20250514")

    def test_get_model_id_openai_mid(self) -> None:
        model = get_model_id("theo", "standard", "openai")
        assert model in ("gpt-4o", "gpt-4o-mini")


class TestBoardPrefixes:
    """Test board prefix constants and helper."""

    def test_all_boards(self) -> None:
        # Core boards required; scenario boards may also be present
        core = {"user", "comms", "company", "agent", "ops"}
        assert core.issubset(set(BOARD_PREFIXES.keys()))

    def test_prefix_values(self) -> None:
        assert BOARD_PREFIXES["user"] == "USR-"
        assert BOARD_PREFIXES["comms"] == "MSG-"
        assert BOARD_PREFIXES["company"] == "REL-"
        assert BOARD_PREFIXES["agent"] == "CYC-"

    def test_get_board_prefix(self) -> None:
        assert get_board_prefix("user") == "USR-"
        assert get_board_prefix("agent") == "CYC-"

    def test_get_board_prefix_unknown_defaults(self) -> None:
        assert get_board_prefix("unknown") == "USR-"


class TestTierSummary:
    """Test the introspection helper."""

    def test_summary_has_expected_keys(self) -> None:
        s = tier_summary("open")
        assert s["tier"] == "open"
        assert "label" in s
        assert "features" in s
        assert "boards" in s
        assert "disabled_agents" in s
        assert "agent_models" in s


class TestScenarioDomains:
    """Test scenario sandbox config loader."""

    def test_domains_loaded(self) -> None:
        domains = get_scenario_domains()
        if not domains:
            pytest.skip("Scenario seed config not in search path")
        assert len(domains) >= 5
        ids = [d["id"] for d in domains]
        assert "professional" in ids
        assert "personal" in ids
        assert "side_venture" in ids

    def test_domain_has_label_and_color(self) -> None:
        domains = get_scenario_domains()
        if not domains:
            pytest.skip("Scenario seed config not in search path")
        for d in domains:
            assert "label" in d, f"Domain {d['id']} missing label"
            assert "color" in d, f"Domain {d['id']} missing color"

    def test_template_for_side_venture(self) -> None:
        domains = get_scenario_domains()
        if not domains:
            pytest.skip("Scenario seed config not in search path")
        t = get_scenario_template("side_venture")
        assert "simulation_variables" in t
        assert "risk_factors" in t

    def test_template_for_unknown_domain_empty(self) -> None:
        t = get_scenario_template("nonexistent")
        assert t == {}
