"""Version check utilities for CLI upgrade notifications.

Checks PyPI for newer versions and caches the result to avoid
slowing down CLI commands.
"""

from __future__ import annotations

import json
import time
from dataclasses import dataclass
from pathlib import Path

import httpx

from terminaluse.version import __version__


@dataclass
class UpdateStatus:
    """Result of a version check."""

    available: str | None = None  # Version string if update exists
    checked: bool = True  # False if fetch failed


# Cache file location (same directory as credentials)
VERSION_CACHE_FILE = Path.home() / ".terminaluse" / "version_cache.json"

# How often to check PyPI (in seconds)
CHECK_INTERVAL_SECONDS = 1 * 60 * 60  # 1 hour

# PyPI API endpoint
PYPI_URL = "https://pypi.org/pypi/terminaluse/json"


def _parse_version(version: str) -> tuple[int, ...]:
    """Parse version string into comparable tuple.

    Handles versions like "0.25.0", "1.0.0", "0.25.0a1", etc.
    Pre-release suffixes are stripped for comparison.
    """
    # Strip any pre-release suffix (a, b, rc, etc.)
    base_version = version.split("a")[0].split("b")[0].split("rc")[0]
    try:
        return tuple(int(x) for x in base_version.split("."))
    except ValueError:
        return (0, 0, 0)


def _is_newer(latest: str, current: str) -> bool:
    """Check if latest version is newer than current."""
    return _parse_version(latest) > _parse_version(current)


def _load_cache() -> dict | None:
    """Load cached version check data."""
    if not VERSION_CACHE_FILE.exists():
        return None
    try:
        return json.loads(VERSION_CACHE_FILE.read_text())
    except (json.JSONDecodeError, OSError):
        return None


def _save_cache(latest_version: str) -> None:
    """Save version check result to cache."""
    cache_dir = VERSION_CACHE_FILE.parent
    cache_dir.mkdir(parents=True, exist_ok=True)

    data = {
        "latest_version": latest_version,
        "checked_at": time.time(),
        "current_version": __version__,
    }

    try:
        VERSION_CACHE_FILE.write_text(json.dumps(data, indent=2))
    except OSError:
        pass  # Ignore write failures


def _fetch_latest_version() -> str | None:
    """Fetch latest version from PyPI.

    Returns:
        Latest version string, or None if fetch failed.
    """
    try:
        with httpx.Client(timeout=3.0) as client:
            response = client.get(PYPI_URL)
            response.raise_for_status()
            data = response.json()
            return data.get("info", {}).get("version")
    except Exception:
        return None


def check_for_updates(force: bool = False) -> UpdateStatus:
    """Check if a newer version is available.

    Uses cached data if recent enough, otherwise fetches from PyPI.

    Args:
        force: If True, bypass cache and always fetch from PyPI.

    Returns:
        UpdateStatus with available version (if any) and whether check succeeded.
    """
    if not force:
        # Check cache first
        cache = _load_cache()
        now = time.time()

        if cache:
            checked_at = cache.get("checked_at", 0)
            cached_version = cache.get("latest_version")

            # Use cache if recent enough
            if now - checked_at < CHECK_INTERVAL_SECONDS and cached_version:
                if _is_newer(cached_version, __version__):
                    return UpdateStatus(available=cached_version)
                return UpdateStatus()

    # Fetch from PyPI
    latest = _fetch_latest_version()

    if latest is None:
        return UpdateStatus(checked=False)

    _save_cache(latest)
    if _is_newer(latest, __version__):
        return UpdateStatus(available=latest)

    return UpdateStatus()
