"""Persistent pseudonymous identity for MPC Tray Watcher update checks."""

from __future__ import annotations

import os
import uuid
from datetime import datetime
from pathlib import Path
from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit


APP_VENDOR = "AmrumSoftware"
APP_PRODUCT = "MPCTrayWatcher"
INSTALLATION_ID_FILENAME = "installation-id.txt"


def default_installation_id_path(local_appdata: str | os.PathLike[str] | None = None) -> Path:
    """Return the per-user persistent identity path."""
    base = Path(local_appdata) if local_appdata else Path(
        os.environ.get("LOCALAPPDATA") or (Path.home() / "AppData" / "Local")
    )
    return base / APP_VENDOR / APP_PRODUCT / INSTALLATION_ID_FILENAME


def normalize_installation_id(value: str) -> str:
    """Validate and normalize a UUID4 string."""
    parsed = uuid.UUID(value.strip())
    if parsed.version != 4:
        raise ValueError("installation_id is not UUID4")
    return str(parsed)


def get_or_create_installation_id(
    path: str | os.PathLike[str] | None = None,
    *,
    uuid_factory=uuid.uuid4,
) -> str:
    """Load the existing UUID4 or atomically create a new one."""
    target = Path(path) if path is not None else default_installation_id_path()
    try:
        return normalize_installation_id(target.read_text(encoding="ascii"))
    except (FileNotFoundError, OSError, UnicodeError, ValueError, AttributeError):
        pass

    installation_id = normalize_installation_id(str(uuid_factory()))
    target.parent.mkdir(parents=True, exist_ok=True)
    temporary = target.with_name(f"{target.name}.{os.getpid()}.tmp")
    try:
        temporary.write_text(installation_id + "\n", encoding="ascii")
        os.replace(temporary, target)
    finally:
        try:
            temporary.unlink(missing_ok=True)
        except OSError:
            pass
    return installation_id


def add_installation_id(url: str, installation_id: str) -> str:
    """Add or replace installation_id while preserving query and fragment."""
    normalized = normalize_installation_id(installation_id)
    parts = urlsplit(url)
    if parts.scheme.casefold() != "https":
        raise ValueError("update URL must use HTTPS")
    query = [(key, value) for key, value in parse_qsl(parts.query, keep_blank_values=True) if key != "installation_id"]
    query.append(("installation_id", normalized))
    return urlunsplit((parts.scheme, parts.netloc, parts.path, urlencode(query), parts.fragment))


def is_daily_update_check_due(last_check_iso: str, *, now: datetime | None = None) -> bool:
    """Return whether no automatic update request was recorded today."""
    current = now or datetime.now()
    if not last_check_iso:
        return True
    try:
        last_check = datetime.fromisoformat(last_check_iso)
    except (TypeError, ValueError):
        return True
    return last_check.date() != current.date()
