"""Tests for version_check module."""

import json
import time
from unittest.mock import patch, MagicMock

import pytest

from appxen_cli.version_check import (
    _parse_version,
    _read_cache,
    _write_cache,
    get_latest_version,
    is_update_available,
    CACHE_TTL,
)


class TestParseVersion:

    def test_simple(self):
        assert _parse_version("0.2.2") == (0, 2, 2)

    def test_major(self):
        assert _parse_version("1.0.0") == (1, 0, 0)

    def test_with_whitespace(self):
        assert _parse_version(" 0.3.1 ") == (0, 3, 1)


class TestCache:

    def test_write_and_read(self, tmp_path, monkeypatch):
        cache_file = tmp_path / "update-check.json"
        monkeypatch.setattr("appxen_cli.version_check.CACHE_FILE", cache_file)
        monkeypatch.setattr("appxen_cli.version_check.CACHE_DIR", tmp_path)

        _write_cache("0.3.0")
        result = _read_cache()
        assert result is not None
        assert result["latest"] == "0.3.0"

    def test_read_missing_file(self, tmp_path, monkeypatch):
        monkeypatch.setattr(
            "appxen_cli.version_check.CACHE_FILE", tmp_path / "nope.json"
        )
        assert _read_cache() is None

    def test_read_expired(self, tmp_path, monkeypatch):
        cache_file = tmp_path / "update-check.json"
        monkeypatch.setattr("appxen_cli.version_check.CACHE_FILE", cache_file)
        # Write a cache entry that's expired (checked_at is 25 hours ago)
        cache_file.write_text(json.dumps({
            "latest": "0.3.0",
            "checked_at": time.time() - CACHE_TTL - 3600,
        }))
        assert _read_cache() is None

    def test_read_fresh(self, tmp_path, monkeypatch):
        cache_file = tmp_path / "update-check.json"
        monkeypatch.setattr("appxen_cli.version_check.CACHE_FILE", cache_file)
        cache_file.write_text(json.dumps({
            "latest": "0.3.0",
            "checked_at": time.time() - 60,  # 1 minute ago
        }))
        result = _read_cache()
        assert result is not None
        assert result["latest"] == "0.3.0"


class TestGetLatestVersion:

    @patch("appxen_cli.version_check.httpx.get")
    def test_success(self, mock_get, tmp_path, monkeypatch):
        monkeypatch.setattr("appxen_cli.version_check.CACHE_FILE", tmp_path / "c.json")
        monkeypatch.setattr("appxen_cli.version_check.CACHE_DIR", tmp_path)

        mock_resp = MagicMock()
        mock_resp.json.return_value = {"version": "0.3.0"}
        mock_resp.raise_for_status = MagicMock()
        mock_get.return_value = mock_resp

        result = get_latest_version(use_cache=False)
        assert result == "0.3.0"
        mock_get.assert_called_once()

    @patch("appxen_cli.version_check.httpx.get")
    def test_cache_fresh_skips_fetch(self, mock_get, tmp_path, monkeypatch):
        cache_file = tmp_path / "c.json"
        monkeypatch.setattr("appxen_cli.version_check.CACHE_FILE", cache_file)
        monkeypatch.setattr("appxen_cli.version_check.CACHE_DIR", tmp_path)
        cache_file.write_text(json.dumps({
            "latest": "0.3.0",
            "checked_at": time.time() - 60,
        }))

        result = get_latest_version(use_cache=True)
        assert result == "0.3.0"
        mock_get.assert_not_called()

    @patch("appxen_cli.version_check.httpx.get")
    def test_cache_expired_fetches(self, mock_get, tmp_path, monkeypatch):
        cache_file = tmp_path / "c.json"
        monkeypatch.setattr("appxen_cli.version_check.CACHE_FILE", cache_file)
        monkeypatch.setattr("appxen_cli.version_check.CACHE_DIR", tmp_path)
        cache_file.write_text(json.dumps({
            "latest": "0.2.0",
            "checked_at": time.time() - CACHE_TTL - 1,
        }))

        mock_resp = MagicMock()
        mock_resp.json.return_value = {"version": "0.3.0"}
        mock_resp.raise_for_status = MagicMock()
        mock_get.return_value = mock_resp

        result = get_latest_version(use_cache=True)
        assert result == "0.3.0"
        mock_get.assert_called_once()

    @patch("appxen_cli.version_check.httpx.get", side_effect=Exception("timeout"))
    def test_network_error_returns_none(self, mock_get, tmp_path, monkeypatch):
        monkeypatch.setattr("appxen_cli.version_check.CACHE_FILE", tmp_path / "c.json")
        monkeypatch.setattr("appxen_cli.version_check.CACHE_DIR", tmp_path)

        result = get_latest_version(use_cache=False)
        assert result is None


class TestIsUpdateAvailable:

    @patch("appxen_cli.version_check.get_latest_version", return_value="0.3.0")
    @patch("appxen_cli.version_check.__version__", "0.2.2")
    def test_newer_available(self, mock_get):
        available, latest = is_update_available()
        assert available is True
        assert latest == "0.3.0"

    @patch("appxen_cli.version_check.get_latest_version", return_value="0.2.2")
    @patch("appxen_cli.version_check.__version__", "0.2.2")
    def test_same_version(self, mock_get):
        available, latest = is_update_available()
        assert available is False
        assert latest is None

    @patch("appxen_cli.version_check.get_latest_version", return_value="0.1.0")
    @patch("appxen_cli.version_check.__version__", "0.2.2")
    def test_older_remote(self, mock_get):
        available, latest = is_update_available()
        assert available is False
        assert latest is None

    @patch("appxen_cli.version_check.get_latest_version", return_value=None)
    def test_unreachable(self, mock_get):
        available, latest = is_update_available()
        assert available is False
        assert latest is None
