"""Catalog client for the Hub update badge and managed tool rows.

The feed model (version compare, entitled rows, update badge) is host-free
(`_core.catalog_core`); fetching it off-thread and redrawing the sidebar is
Blender's half.
"""

from __future__ import annotations

import threading

import bpy

from . import host
from ._core import config
from ._core.catalog_core import CatalogCache, newer_version  # noqa: F401 — re-exported for panels

_CACHE = CatalogCache()

# Last fetched catalog: {"hub": version-or-None, "data": full-response-or-None}.
_LATEST = _CACHE.latest

hub_latest = _CACHE.hub_latest
addons = _CACHE.addons
addon = _CACHE.addon
installed_hub_version = host.hub_version


def update_available() -> bool:
    return _CACHE.update_available(installed_hub_version())


def check_async():
    """Fetch the catalog off-thread; the panel redraws when it lands.

    Rides the stored credential when there is one — the per-addon `entitled`
    flags are only real with a Bearer, so login/sign-out must re-call this to
    flip the panel's locks.
    """
    if not host.online_allowed():
        return
    site = host.site_url()
    credential = config.load_credential(site)
    token = (credential or {}).get("token")

    def worker():
        try:
            status, data = host.catalog(site, token=token)
            if status == 200 and isinstance(data, dict):
                _CACHE.store(data)
        except Exception:
            pass  # offline / route not deployed — no badge, no noise
        bpy.app.timers.register(_redraw_once, first_interval=0.0)

    threading.Thread(target=worker, daemon=True).start()


def _redraw_once():
    for window in bpy.context.window_manager.windows:
        for area in window.screen.areas:
            if area.type == "VIEW_3D":
                area.tag_redraw()
    return None
