"""version_check 模块单测。"""

from __future__ import annotations

import json

import pytest

from xiangqin import version_check as vc


@pytest.fixture(autouse=True)
def isolate_cache(tmp_path, monkeypatch):
    """把 ~/.xiangqin 指到 tmp_path，防污染用户机。"""
    monkeypatch.setenv("XIANGQIN_CONFIG_DIR", str(tmp_path / ".xiangqin"))
    monkeypatch.delenv("XIANGQIN_NO_UPDATE_CHECK", raising=False)
    monkeypatch.delenv("CI", raising=False)
    yield


# ---------- 版本比较 ----------


def test_version_less_basic():
    assert vc._version_less("0.3.0", "0.4.0") is True
    assert vc._version_less("0.3.0", "0.3.1") is True
    assert vc._version_less("0.3.0", "0.3.0") is False
    assert vc._version_less("0.4.0", "0.3.9") is False


def test_version_less_dev_suffix():
    # dev 后缀忽略，按前 3 位数字比
    assert vc._version_less("0.3.0.dev1", "0.3.1") is True
    assert vc._version_less("0.3.0.dev1", "0.3.0") is False  # 相等（前3位）


def test_version_less_handles_partial():
    assert vc._version_less("0.3", "0.3.1") is True  # (0,3) < (0,3,1)
    assert vc._parse_version("") == ()


# ---------- 缓存读写 ----------


def test_save_and_load_cache():
    vc._save_cache("0.4.0")
    cache = vc._load_cache()
    assert cache["remote_latest"] == "0.4.0"
    assert isinstance(cache["last_checked_at"], int)


def test_load_cache_missing():
    assert vc._load_cache() is None


def test_load_cache_corrupt(tmp_path, monkeypatch):
    monkeypatch.setenv("XIANGQIN_CONFIG_DIR", str(tmp_path / ".xiangqin"))
    (tmp_path / ".xiangqin").mkdir(mode=0o700)
    (tmp_path / ".xiangqin" / "version-cache.json").write_text("{ corrupt json")
    assert vc._load_cache() is None  # 损坏返 None


# ---------- print_update_notice_if_needed ----------


def test_no_cache_no_print(monkeypatch, capsys):
    """首次调用：无缓存，不应 stderr 打印（只后台 refresh）。"""
    monkeypatch.setattr(vc, "_spawn_background_refresh", lambda: None)
    vc.print_update_notice_if_needed()
    err = capsys.readouterr().err
    assert err == ""


def test_print_when_remote_newer(monkeypatch, capsys):
    """缓存有更新版本 → stderr 打印提示。"""
    monkeypatch.setattr(vc, "__version__", "0.3.0")
    vc._save_cache("0.4.0")
    monkeypatch.setattr(vc, "_spawn_background_refresh", lambda: None)
    vc.print_update_notice_if_needed()
    err = capsys.readouterr().err
    assert "[xq] 新版本 0.4.0 可用" in err
    assert "0.3.0" in err
    assert "pip install -U acong-tech-xiangqin" in err


def test_no_print_when_up_to_date(monkeypatch, capsys):
    """本地 == 远程，不打印。"""
    monkeypatch.setattr(vc, "__version__", "0.4.0")
    vc._save_cache("0.4.0")
    monkeypatch.setattr(vc, "_spawn_background_refresh", lambda: None)
    vc.print_update_notice_if_needed()
    err = capsys.readouterr().err
    assert err == ""


def test_no_print_when_local_newer(monkeypatch, capsys):
    """本地 > 远程（比如跑 dev 版），不打印。"""
    monkeypatch.setattr(vc, "__version__", "0.5.0")
    vc._save_cache("0.4.0")
    monkeypatch.setattr(vc, "_spawn_background_refresh", lambda: None)
    vc.print_update_notice_if_needed()
    err = capsys.readouterr().err
    assert err == ""


def test_disabled_by_env(monkeypatch, capsys):
    monkeypatch.setenv("XIANGQIN_NO_UPDATE_CHECK", "1")
    monkeypatch.setattr(vc, "__version__", "0.3.0")
    vc._save_cache("0.4.0")
    # 即使有缓存 + 有更新，也不打印
    vc.print_update_notice_if_needed()
    err = capsys.readouterr().err
    assert err == ""


def test_disabled_by_ci(monkeypatch, capsys):
    monkeypatch.setenv("CI", "true")
    monkeypatch.setattr(vc, "__version__", "0.3.0")
    vc._save_cache("0.4.0")
    vc.print_update_notice_if_needed()
    err = capsys.readouterr().err
    assert err == ""


def test_refresh_spawned_when_stale(monkeypatch):
    """缓存 >24h → 后台 refresh 应被 spawn。"""
    import time

    # 伪造 25h 前的缓存

    cache_p = vc._cache_path()
    cache_p.parent.mkdir(mode=0o700, exist_ok=True)
    cache_p.write_text(
        json.dumps({"last_checked_at": int(time.time()) - 25 * 3600, "remote_latest": "0.3.0"})
    )
    spawned = []
    monkeypatch.setattr(vc, "_spawn_background_refresh", lambda: spawned.append(True))
    vc.print_update_notice_if_needed()
    assert spawned == [True]


def test_refresh_not_spawned_when_fresh(monkeypatch):
    """缓存 <24h → 不 spawn。"""
    vc._save_cache("0.3.0")  # 刚写的
    spawned = []
    monkeypatch.setattr(vc, "_spawn_background_refresh", lambda: spawned.append(True))
    vc.print_update_notice_if_needed()
    assert spawned == []


# ---------- _fetch_remote（网络失败静默） ----------


def test_fetch_remote_network_fail(monkeypatch):
    """urllib 失败时返 None，不抛。"""

    def boom(*a, **kw):
        raise OSError("no network")

    monkeypatch.setattr(vc.urllib.request, "urlopen", boom)
    assert vc._fetch_remote() is None


def test_fetch_remote_happy(monkeypatch):
    """mock urllib 返 PyPI JSON，取 info.version。"""

    class FakeResp:
        def __init__(self, body):
            self._body = body

        def read(self):
            return self._body

        def __enter__(self):
            return self

        def __exit__(self, *a):
            return False

    body = json.dumps({"info": {"version": "9.9.9"}}).encode()
    monkeypatch.setattr(vc.urllib.request, "urlopen", lambda *a, **kw: FakeResp(body))
    assert vc._fetch_remote() == "9.9.9"
