"""Blender host adapter — everything `_core` needs to know about this DCC.

One file per host (docs/plans/three-blocks-cinema4d-addon.md §3): the constants
the shared core is parameterized on, plus site/label/version resolution and the
three `_core.api` calls bound to them. Porting to another DCC starts by copying
this file and changing the six constants.
"""

from __future__ import annotations

import platform
import re
import sys
from pathlib import Path

import bpy

from ._core import api

HOST_KEY = "blender"  # ~/.three-blocks/blender/{addons,installed.json}
CLIENT_ID = "blender-addon"  # device-flow client (free-form server-side)
VALIDATE_TOOL = "blender-hub"  # /api/tools/validate `tool` — telemetry only
CATALOG_PATH = "/api/blender/catalog"
EVENT_PATH = "/api/analytics/v2/blender-event"  # the route assigns source=blender
EVENT_SOURCE = "blender"  # telemetry idempotency namespace


def site_url() -> str:
    """The hub's effective site — TB_SITE_URL → prefs override → prod, so a
    Dock-launched Blender pointed at a sandbox hands tools the sandbox token."""
    from . import prefs

    return prefs.effective_site_url()


def label() -> str:
    return f"Blender {bpy.app.version_string}"


def host_version() -> str:
    """Dotted host version for tb_addon.json minimum checks (manager_core)."""
    return ".".join(str(part) for part in bpy.app.version)


def online_allowed() -> bool:
    """Blender's Preferences ▸ System ▸ Allow Online Access. Cinema 4D has no
    equivalent, so its adapter returns True — keep the hook, not the flag."""
    return bool(getattr(bpy.app, "online_access", True))


def hub_version() -> str:
    # Read our own manifest file — Blender's extension loader STRIPS the
    # module's bl_info (verified on 5.2), so the attribute can't be trusted.
    manifest = Path(__file__).with_name("blender_manifest.toml")
    try:
        match = re.search(r'^version\s*=\s*"([^"]+)"', manifest.read_text("utf-8"), re.M)
        if match:
            return match.group(1)
    except OSError:
        pass
    info = getattr(sys.modules.get(__package__), "bl_info", None)  # legacy installs
    return ".".join(str(part) for part in info["version"]) if info else "0.0.0"


def validate(site: str, token: str):
    return api.validate(site, token, tool=VALIDATE_TOOL, tool_version=hub_version(), label=label())


def catalog(site: str, token: str | None = None):
    return api.catalog(site, token=token, path=CATALOG_PATH)


def login_flow(site, emit, should_stop=lambda: False, **kwargs):
    return api.login_flow(
        site,
        emit,
        should_stop,
        client_id=CLIENT_ID,
        device_name=platform.node() or "Blender",
        validate_credential=validate,
        **kwargs,
    )
