"""
Version check module: query PyPI at startup, prompt for upgrade if newer version exists.

Design:
- Background thread query, does not block startup (async mode)
- Synchronous blocking mode: prompt user to upgrade, auto-restart after upgrade
- Silent failure when network unavailable
- Check at most once per 24 hours (cached in runtime dir)
- Query timeout 5 seconds
"""
from __future__ import annotations

import json
import os
import subprocess
import sys
import threading
import time
import urllib.request
from datetime import datetime, timedelta
from pathlib import Path
from typing import Optional

from bridgeflow import __version__

PYPI_URL = "https://pypi.org/pypi/bridgeflow/json"
CACHE_FILE_NAME = "version_check_cache.json"
CHECK_INTERVAL_HOURS = 24
REQUEST_TIMEOUT_SECONDS = 5


def _parse_version(v: str) -> tuple[int, ...]:
    try:
        return tuple(int(x) for x in v.strip().split("."))
    except Exception:
        return (0,)


def _cache_path(runtime_dir: Optional[str]) -> Path:
    if runtime_dir:
        return Path(runtime_dir) / CACHE_FILE_NAME
    import tempfile
    return Path(tempfile.gettempdir()) / "bridgeflow" / CACHE_FILE_NAME


def _load_cache(path: Path) -> dict:
    try:
        if path.exists():
            return json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        pass
    return {}


def _save_cache(path: Path, data: dict) -> None:
    try:
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
    except Exception:
        pass


def _fetch_latest_version() -> Optional[str]:
    """Fetch latest version from PyPI; returns None on timeout/failure."""
    try:
        req = urllib.request.Request(
            PYPI_URL,
            headers={"Accept": "application/json", "User-Agent": f"bridgeflow/{__version__}"},
        )
        with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT_SECONDS) as resp:
            data = json.loads(resp.read().decode("utf-8"))
            return data["info"]["version"]
    except Exception:
        return None


def _should_check(cache: dict) -> bool:
    """Only re-query if last check was more than 24 hours ago."""
    last = cache.get("last_checked")
    if not last:
        return True
    try:
        return datetime.now() - datetime.fromisoformat(last) > timedelta(hours=CHECK_INTERVAL_HOURS)
    except Exception:
        return True


def _get_latest_cached_or_fetch(runtime_dir: Optional[str]) -> Optional[str]:
    """Return latest version (prefer cache, fetch from PyPI if expired)."""
    path = _cache_path(runtime_dir)
    cache = _load_cache(path)

    if _should_check(cache):
        latest = _fetch_latest_version()
        cache["last_checked"] = datetime.now().isoformat()
        if latest:
            cache["latest_version"] = latest
        _save_cache(path, cache)
        return latest
    return cache.get("latest_version")


def _do_upgrade_and_restart() -> None:
    """Run pip upgrade; restart process on success."""
    print("\n  Upgrading bridgeflow...\n")
    result = subprocess.run(
        [sys.executable, "-m", "pip", "install", "--upgrade", "bridgeflow"],
        check=False,
    )
    if result.returncode != 0:
        print("  Upgrade failed. Please run manually: pip install --upgrade bridgeflow")
        return

    print("\n  Upgrade complete, restarting...\n")
    try:
        os.execv(sys.argv[0], sys.argv)
    except Exception:
        subprocess.Popen([sys.argv[0]] + sys.argv[1:])
        sys.exit(0)


# ── Public API ────────────────────────────────────────────────────────────────

def check_update_async(runtime_dir: Optional[str] = None) -> None:
    """
    Background thread: check for updates, print notice if newer version found.
    Non-interactive; suitable for scripts/automation.
    """
    def _worker() -> None:
        try:
            latest = _get_latest_cached_or_fetch(runtime_dir)
            if latest and _parse_version(latest) > _parse_version(__version__):
                print()
                print("  +---------------------------------------------------+")
                print(f"  |  New version available: v{latest} (current v{__version__})")
                print(f"  |  Upgrade: pip install --upgrade bridgeflow")
                print("  +---------------------------------------------------+")
                print()
        except Exception:
            pass

    t = threading.Thread(target=_worker, daemon=True)
    t.start()
    time.sleep(0.3)


def check_update_interactive(runtime_dir: Optional[str] = None,
                             auto_upgrade: bool = False) -> None:
    """
    Synchronous check: prompt user to upgrade if newer version found.
    Auto-restarts after successful upgrade.

    Args:
        runtime_dir:   Cache directory (usually config.runtime_dir)
        auto_upgrade:  If True, skip confirmation and upgrade immediately
    """
    try:
        latest = _get_latest_cached_or_fetch(runtime_dir)
    except Exception:
        return

    if not latest or _parse_version(latest) <= _parse_version(__version__):
        return

    print()
    print("  +===================================================+")
    print(f"  |  New version: v{latest}  (current: v{__version__})")
    print(f"  |  Changelog: https://github.com/joinwell52-ai/BridgeFlow/blob/main/CHANGELOG.md")
    print("  +===================================================+")

    if auto_upgrade:
        _do_upgrade_and_restart()
        return

    try:
        answer = input("  Upgrade and restart now? [y/N] ").strip().lower()
    except (EOFError, KeyboardInterrupt):
        answer = "n"

    if answer in ("y", "yes"):
        _do_upgrade_and_restart()
    else:
        print("  Skipped upgrade, continuing...\n")
