"""Shared geolocation singleton.

Runs backend/geolocate.py (IP geolocation, cached) exactly once and notifies
subscribers. Both the Location map and the Weather widget subscribe, so there is a
single source of truth for "where am I" and only one network lookup.
"""

from __future__ import annotations

import sys
from typing import Callable, Optional

from lib.proc import run_json
from paths import BACKEND_DIR


class LocationService:
    def __init__(self) -> None:
        self.data: Optional[dict] = None
        self._subs: list[Callable[[dict], None]] = []
        self._inflight = False

    def subscribe(self, cb: Callable[[dict], None]) -> None:
        self._subs.append(cb)
        if self.data is not None:
            cb(self.data)

    def get(self) -> Optional[dict]:
        if self.data is None and not self._inflight:
            self.refresh()
        return self.data

    def refresh(self) -> None:
        if self._inflight:
            return
        self._inflight = True
        argv = [sys.executable, str(BACKEND_DIR / "geolocate.py")]
        run_json(argv, self._on_result)

    def _on_result(self, ok: bool, data) -> None:
        self._inflight = False
        if ok and isinstance(data, dict) and "lat" in data:
            self.data = data
            for cb in list(self._subs):
                cb(data)


_instance: LocationService | None = None


def get_location_service() -> LocationService:
    global _instance
    if _instance is None:
        _instance = LocationService()
    return _instance
