from __future__ import annotations

from dataclasses import dataclass
import json
from pathlib import Path
import re
from typing import Any


APP_ROOT = Path(__file__).resolve().parent.parent
VERSION_FILE = APP_ROOT / "version.json"


@dataclass(frozen=True)
class AppVersionInfo:
    app_id: str
    name: str
    version: str
    channel: str
    auth_required: bool
    auth_server_url: str
    offline_grace_days: int
    update_enabled: bool


def _read_json(path: Path) -> dict[str, Any]:
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
    except FileNotFoundError:
        return {}
    if not isinstance(data, dict):
        return {}
    return data


def load_version_info(path: Path | None = None) -> AppVersionInfo:
    data = _read_json(path or VERSION_FILE)
    auth = data.get("auth") if isinstance(data.get("auth"), dict) else {}
    update = data.get("update") if isinstance(data.get("update"), dict) else {}
    return AppVersionInfo(
        app_id=str(data.get("app_id") or "hydrology-calculation-software"),
        name=str(data.get("name") or "水文计算软件"),
        version=str(data.get("version") or "0.0.0"),
        channel=str(data.get("channel") or "stable"),
        auth_required=bool(auth.get("required", False)),
        auth_server_url=str(auth.get("server_url") or "http://127.0.0.1:8000"),
        offline_grace_days=max(int(auth.get("offline_grace_days", 7)), 0),
        update_enabled=bool(update.get("enabled", True)),
    )


def parse_version(version: str) -> tuple[int, ...]:
    parts = re.findall(r"\d+", version)
    if not parts:
        return (0,)
    return tuple(int(part) for part in parts)


def compare_versions(left: str, right: str) -> int:
    left_parts = parse_version(left)
    right_parts = parse_version(right)
    max_len = max(len(left_parts), len(right_parts))
    left_padded = left_parts + (0,) * (max_len - len(left_parts))
    right_padded = right_parts + (0,) * (max_len - len(right_parts))
    if left_padded < right_padded:
        return -1
    if left_padded > right_padded:
        return 1
    return 0
