"""Lightweight version checks and upgrade helpers for the CLI."""

from __future__ import annotations

import json
import shutil
import subprocess
from datetime import datetime, timedelta
from urllib.error import URLError
from urllib.request import urlopen

from superpitch import __version__
from superpitch.state import load_config, save_config

PYPI_JSON_URL = "https://pypi.org/pypi/superpitch/json"
UPDATE_CHECK_INTERVAL = timedelta(hours=12)


def parse_version(version: str) -> tuple[int, ...]:
    return tuple(int("".join(c for c in p if c.isdigit()) or "0") for p in version.split("."))


def is_newer_version(candidate: str, current: str = __version__) -> bool:
    return parse_version(candidate) > parse_version(current)


def should_check_for_updates(config: dict, now: datetime | None = None) -> bool:
    last_check = (config.get("last_update_check_at") or "").strip()
    if not last_check:
        return True
    try:
        checked_at = datetime.fromisoformat(last_check)
    except ValueError:
        return True
    now = now or datetime.now()
    return now - checked_at >= UPDATE_CHECK_INTERVAL


def fetch_latest_version(timeout: float = 1.5) -> str | None:
    try:
        with urlopen(PYPI_JSON_URL, timeout=timeout) as response:
            payload = json.load(response)
    except (URLError, TimeoutError, json.JSONDecodeError, OSError):
        return None
    info = payload.get("info") or {}
    version = str(info.get("version") or "").strip()
    return version or None


def refresh_update_status(force: bool = False) -> str | None:
    config = load_config()
    now = datetime.now()
    if not force and not should_check_for_updates(config, now=now):
        latest = (config.get("latest_version_available") or "").strip()
        return latest or None

    latest = fetch_latest_version()
    config["last_update_check_at"] = now.isoformat()
    if latest:
        config["latest_version_available"] = latest
    save_config(config)
    return latest


def get_update_notice(force: bool = False) -> str | None:
    latest = refresh_update_status(force=force)
    if latest and is_newer_version(latest):
        return latest
    return None


def run_upgrade() -> tuple[bool, str]:
    uv = shutil.which("uv")
    if not uv:
        return False, "uv is not installed. Install it: curl -LsSf https://astral.sh/uv/install.sh | sh"

    try:
        completed = subprocess.run(
            [uv, "tool", "upgrade", "superpitch"],
            capture_output=True,
            text=True,
            check=False,
        )
    except OSError as exc:
        return False, str(exc)

    output = "\n".join(
        part.strip() for part in [completed.stdout, completed.stderr] if part.strip()
    ).strip()
    if completed.returncode == 0:
        return True, output or "Superpitch upgraded."
    return False, output or "Upgrade failed."
