import pytest
from mars_bot.tgstat import (
    get_mentions,
    normalize_username,
    is_self_mention,
    TGStatError,
)


def _mock_response(monkeypatch, json_data, status_code=200):
    """Простой мок requests.get → объект с .json()/.raise_for_status()."""
    class FakeResp:
        def __init__(self):
            self.status_code = status_code
        def json(self):
            return json_data
        def raise_for_status(self):
            if self.status_code >= 400:
                import requests
                raise requests.HTTPError(f"{self.status_code}")
    import mars_bot.tgstat as mod
    captured = {}
    def fake_get(url, params=None, timeout=None):
        captured["url"] = url
        captured["params"] = params
        return FakeResp()
    monkeypatch.setattr(mod.requests, "get", fake_get)
    return captured


def test_get_mentions_happy(monkeypatch):
    sample = {
        "status": "ok",
        "response": {
            "items": [
                {"mentionId": 1, "mentionType": "channel", "postId": 100,
                 "postLink": "https://t.me/x/1", "postDate": 1700000000, "channelId": 9},
            ],
            "channels": [
                {"id": 9, "username": "@x", "title": "X", "participants_count": 10,
                 "link": "t.me/x"},
            ],
        },
    }
    captured = _mock_response(monkeypatch, sample)
    result = get_mentions(token="tok", channel_id="@marsingru", extended=True, limit=50)

    assert result["items"][0]["postId"] == 100
    assert result["channels"][0]["username"] == "@x"
    assert captured["url"] == "https://api.tgstat.ru/channels/mentions"
    assert captured["params"]["token"] == "tok"
    assert captured["params"]["channelId"] == "@marsingru"
    assert captured["params"]["extended"] == 1
    assert captured["params"]["limit"] == 50


def test_get_mentions_empty_response_normalized(monkeypatch):
    """TGStat возвращает response=[] (list, не dict) когда упоминаний нет —
    клиент должен нормализовать к {"items": [], "channels": []}, иначе callers
    падают на .get() по list-у. Реальный кейс с @natashhhh 2026-06-09."""
    _mock_response(monkeypatch, {"status": "ok", "response": []})
    result = get_mentions(token="t", channel_id="@quietchannel")
    assert result == {"items": [], "channels": []}


def test_get_mentions_raises_on_status_not_ok(monkeypatch):
    _mock_response(monkeypatch, {"status": "error", "error": "bad token"})
    with pytest.raises(TGStatError, match="TGStat error: bad token"):
        get_mentions(token="bad", channel_id="@x")


def test_get_mentions_raises_on_http_error(monkeypatch):
    import requests
    import mars_bot.tgstat as mod
    def boom(url, params=None, timeout=None):
        raise requests.ConnectionError("network down")
    monkeypatch.setattr(mod.requests, "get", boom)
    with pytest.raises(TGStatError, match="HTTP request failed"):
        get_mentions(token="t", channel_id="@x")


def test_http_error_masks_token(monkeypatch):
    """RequestException с токеном в URL не должен утекать в текст TGStatError."""
    import requests
    import mars_bot.tgstat as mod

    def boom(url, params=None, timeout=None):
        raise requests.ConnectionError(
            "url https://api.tgstat.ru/channels/mentions?token=SUPERSECRET123&channelId=@x"
        )
    monkeypatch.setattr(mod.requests, "get", boom)
    with pytest.raises(TGStatError) as ei:
        get_mentions(token="SUPERSECRET123", channel_id="@x")
    assert "SUPERSECRET123" not in str(ei.value)
    assert "token=***" in str(ei.value)


def test_normalize_username():
    assert normalize_username("@MarsInGru") == "marsingru"
    assert normalize_username("marsingru") == "marsingru"
    assert normalize_username("  @MarsInGru  ") == "marsingru"
    assert normalize_username("") is None
    assert normalize_username(None) is None
    assert normalize_username("@") is None  # only sigil → effectively empty


def test_is_self_mention_true_cases():
    tracked = {"marsingru", "choooooooir", "natashhhh"}
    assert is_self_mention("@marsingru", tracked) is True
    assert is_self_mention("MARSINGRU", tracked) is True
    assert is_self_mention("  @MarsInGru  ", tracked) is True


def test_is_self_mention_false_cases():
    tracked = {"marsingru"}
    assert is_self_mention("@somebody", tracked) is False
    assert is_self_mention(None, tracked) is False  # неизвестный источник — НЕ self
    assert is_self_mention("", tracked) is False
