import json
import pytest
from pathlib import Path
from mars_bot.config import load_config, ConfigError
from mars_bot.config import load_mentions_config, MentionsConfig


@pytest.fixture(autouse=True)
def _clean_env(monkeypatch):
    # load_dotenv mutates os.environ; clear TELEGRAM_BOT_TOKEN between tests
    # so leakage from one test cannot mask a missing/invalid value in another.
    monkeypatch.delenv("TELEGRAM_BOT_TOKEN", raising=False)


def test_load_config_happy_path(tmp_path: Path):
    (tmp_path / ".env").write_text("TELEGRAM_BOT_TOKEN=test-token\n")
    chats = {"team": -100123, "test": 42}
    (tmp_path / "chats.json").write_text(json.dumps(chats))

    cfg = load_config(tmp_path)
    assert cfg.bot_token == "test-token"
    assert cfg.chats == {"team": -100123, "test": 42}


def test_load_config_missing_env(tmp_path: Path):
    with pytest.raises(ConfigError, match=".env not found"):
        load_config(tmp_path)


def test_load_config_missing_token(tmp_path: Path):
    (tmp_path / ".env").write_text("OTHER=x\n")
    (tmp_path / "chats.json").write_text('{"team": 1}')
    with pytest.raises(ConfigError, match="TELEGRAM_BOT_TOKEN missing"):
        load_config(tmp_path)


def test_load_config_invalid_json(tmp_path: Path):
    (tmp_path / ".env").write_text("TELEGRAM_BOT_TOKEN=t\n")
    (tmp_path / "chats.json").write_text("not json")
    with pytest.raises(ConfigError, match="not valid JSON"):
        load_config(tmp_path)


def test_load_config_non_int_chat_id(tmp_path: Path):
    (tmp_path / ".env").write_text("TELEGRAM_BOT_TOKEN=t\n")
    (tmp_path / "chats.json").write_text('{"team": "not-int"}')
    with pytest.raises(ConfigError, match="must be int"):
        load_config(tmp_path)


def test_load_config_empty_chats(tmp_path: Path):
    (tmp_path / ".env").write_text("TELEGRAM_BOT_TOKEN=t\n")
    (tmp_path / "chats.json").write_text("{}")
    with pytest.raises(ConfigError, match="at least one alias"):
        load_config(tmp_path)


def test_load_config_skips_underscore_keys(tmp_path: Path):
    """Ключи с префиксом '_' — служебные блоки, не чаты. Не валидировать как int."""
    (tmp_path / ".env").write_text("TELEGRAM_BOT_TOKEN=t\n")
    chats = {
        "team": -100123,
        "test": 42,
        "_mentions": {"tracked": {"marsingru": "team"}},
    }
    (tmp_path / "chats.json").write_text(json.dumps(chats))

    cfg = load_config(tmp_path)
    assert cfg.chats == {"team": -100123, "test": 42}
    assert "_mentions" not in cfg.chats


def test_load_mentions_config_happy(tmp_path: Path):
    chats = {
        "team": -100123,
        "test": 42,
        "_mentions": {"tracked": {"marsingru": "team", "natashhhh": "test"}},
    }
    (tmp_path / "chats.json").write_text(json.dumps(chats))

    mc = load_mentions_config(tmp_path)
    assert isinstance(mc, MentionsConfig)
    assert mc.tracked == {"marsingru": "team", "natashhhh": "test"}


def test_load_mentions_config_returns_none_when_no_block(tmp_path: Path):
    (tmp_path / "chats.json").write_text('{"team": 1}')
    assert load_mentions_config(tmp_path) is None


def test_load_mentions_config_alert_to(tmp_path: Path):
    chats = {
        "team": -100123,
        "test": 42,
        "_mentions": {"alert_to": "test", "tracked": {"marsingru": "team"}},
    }
    (tmp_path / "chats.json").write_text(json.dumps(chats))
    mc = load_mentions_config(tmp_path)
    assert mc.alert_to == "test"


def test_load_mentions_config_alert_to_defaults_none(tmp_path: Path):
    chats = {"team": 1, "_mentions": {"tracked": {"marsingru": "team"}}}
    (tmp_path / "chats.json").write_text(json.dumps(chats))
    assert load_mentions_config(tmp_path).alert_to is None


def test_load_mentions_config_alert_to_unknown_alias(tmp_path: Path):
    chats = {"team": 1, "_mentions": {"alert_to": "ghost", "tracked": {"marsingru": "team"}}}
    (tmp_path / "chats.json").write_text(json.dumps(chats))
    with pytest.raises(ConfigError, match="unknown _mentions.alert_to alias 'ghost'"):
        load_mentions_config(tmp_path)


def test_load_mentions_config_unknown_destination(tmp_path: Path):
    chats = {
        "team": -100123,
        "_mentions": {"tracked": {"marsingru": "nonexistent"}},
    }
    (tmp_path / "chats.json").write_text(json.dumps(chats))
    with pytest.raises(ConfigError, match="unknown destination alias 'nonexistent'"):
        load_mentions_config(tmp_path)


def test_load_mentions_config_missing_tracked_key(tmp_path: Path):
    chats = {"team": 1, "_mentions": {"something_else": {}}}
    (tmp_path / "chats.json").write_text(json.dumps(chats))
    with pytest.raises(ConfigError, match="_mentions block missing 'tracked'"):
        load_mentions_config(tmp_path)


def test_load_mentions_config_block_not_object(tmp_path: Path):
    (tmp_path / "chats.json").write_text('{"team": 1, "_mentions": "oops"}')
    with pytest.raises(ConfigError, match="_mentions block must be an object"):
        load_mentions_config(tmp_path)


def test_load_mentions_config_tracked_not_object(tmp_path: Path):
    (tmp_path / "chats.json").write_text('{"team": 1, "_mentions": {"tracked": "oops"}}')
    with pytest.raises(ConfigError, match="_mentions.tracked must be an object"):
        load_mentions_config(tmp_path)
