"""
Background analytics helpers for the CGHEVEN DaVinci Resolve addon.

Sends events to Strapi: POST {LICENSE_SERVER}/api/analytics/track
Strapi forwards to PostHog. No local storage.
"""

from __future__ import annotations

import hashlib
import json
import platform
import random
import threading
import urllib.request
from typing import Any, Dict, Tuple

# Platform identifier sent in every analytics event.
# Mac wrapper patches this to "davinci_resolve_mac" after loading this module.
HOST_APP = "davinci_resolve"


def _safe_str(x: Any) -> str:
    try:
        return "" if x is None else str(x)
    except Exception:
        return ""


def anonymize_distinct_id(raw_id: str) -> str:
    """
    PostHog distinctId should not contain secrets (session tokens).
    We hash whatever we get into a stable anonymous id.
    """
    rid = (raw_id or "").strip()
    if not rid:
        rid = "unknown"
    return hashlib.sha256(rid.encode("utf-8")).hexdigest()


def _parse_asset(asset: Dict[str, Any] | None) -> Tuple[Dict[str, Any], str, str]:
    try:
        a = (asset or {}).get("attributes", asset or {}) if asset else {}
        cat = a.get("categorie", {}) or {}
        cat_name = cat.get("Name", "") if isinstance(cat, dict) else _safe_str(cat)
        subcats = a.get("subcategories", []) or []
        subcat_name = (
            subcats[0].get("Name", "")
            if subcats and isinstance(subcats[0], dict)
            else ""
        )
        return a, _safe_str(cat_name), _safe_str(subcat_name)
    except Exception:
        return {}, "", ""


def _post_event(
    *,
    license_server: str,
    addon_slug: str,
    event_name: str,
    distinct_id: str,
    properties: Dict[str, Any],
) -> None:
    try:
        payload = {
            "event": event_name,
            "license_key": distinct_id,
            "addon_name": addon_slug,
            "properties": properties or {},
        }

        url = (license_server or "").rstrip("/") + "/api/analytics/track"
        req = urllib.request.Request(
            url,
            data=json.dumps(payload).encode("utf-8"),
            headers={
                "Content-Type": "application/json",
                "User-Agent": "CGHEVEN-DaVinci/Analytics",
                "Accept": "application/json",
            },
            method="POST",
        )
        with urllib.request.urlopen(req, timeout=5):
            pass
    except Exception:
        # Never break the addon due to analytics
        return


def _send_async(fn, *args, **kwargs) -> None:
    try:
        threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
    except Exception:
        return


def _should_sample(sample_rate: float) -> bool:
    try:
        sr = float(sample_rate)
        if sr >= 1.0:
            return True
        if sr <= 0.0:
            return False
        return random.random() < sr
    except Exception:
        return True


def send_addon_installed(
    *,
    license_server: str,
    addon_slug: str,
    addon_version: str,
    distinct_id: str,
) -> None:
    """Sirf ek baar fire hota hai — pehli install pe."""
    def _send() -> None:
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name="addon_installed",
            distinct_id=distinct_id,
            properties={"addon_version": addon_version, "host_app": HOST_APP},
        )
    _send_async(_send)


def send_event(
    *,
    license_server: str,
    addon_slug: str,
    addon_version: str,
    distinct_id: str,
    event_name: str,
    properties: Dict[str, Any] | None = None,
) -> None:
    """Generic event sender — used for the update-funnel analytics
    (addon_opened / update_prompt_shown / update_completed)."""
    def _send() -> None:
        props = dict(properties or {})
        props.setdefault("addon_version", addon_version)
        props.setdefault("host_app", HOST_APP)
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name=event_name,
            distinct_id=distinct_id,
            properties=props,
        )
    _send_async(_send)


def send_license_activated(
    *,
    license_server: str,
    addon_slug: str,
    addon_version: str,
    distinct_id: str,
) -> None:
    def _send() -> None:
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name="license_activated",
            distinct_id=distinct_id,
            properties={"addon_version": addon_version, "host_app": HOST_APP},
        )
    _send_async(_send)


def send_license_expired(
    *,
    license_server: str,
    addon_slug: str,
    distinct_id: str,
) -> None:
    def _send() -> None:
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name="license_expired",
            distinct_id=distinct_id,
            properties={"host_app": HOST_APP},
        )
    _send_async(_send)


def send_download_failed(
    *,
    license_server: str,
    addon_slug: str,
    distinct_id: str,
    asset: Dict[str, Any] | None = None,
    http_status: int = 0,
    error: str = "",
) -> None:
    def _send() -> None:
        a, _, _ = _parse_asset(asset)
        if http_status == 403:
            reason = "Authentication expired"
        elif http_status == 404:
            reason = "File not found on CDN"
        elif http_status >= 500:
            reason = f"Server returned {http_status} Internal Error"
        elif http_status == 0:
            reason = "Network timeout or DNS resolution failed"
        else:
            reason = _safe_str(error) or f"HTTP {http_status} error"
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name="download_failed",
            distinct_id=distinct_id,
            properties={
                "asset_id":    _safe_str((asset or {}).get("id", "")),
                "asset_name":  _safe_str(a.get("Title", a.get("title", "Unknown"))),
                "http_status": http_status,
                "reason":      reason,
                "host_app":    HOST_APP,
            },
        )
    _send_async(_send)


def send_import_failed(
    *,
    license_server: str,
    addon_slug: str,
    distinct_id: str,
    asset: Dict[str, Any] | None = None,
    error: str = "",
) -> None:
    def _send() -> None:
        a, _, _ = _parse_asset(asset)
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name="import_failed",
            distinct_id=distinct_id,
            properties={
                "asset_id":   _safe_str((asset or {}).get("id", "")),
                "asset_name": _safe_str(a.get("Title", a.get("title", "Unknown"))),
                "reason":     _safe_str(error)[:240] or "unknown",
                "host_app":   HOST_APP,
            },
        )
    _send_async(_send)


def send_favourite_added(
    *,
    license_server: str,
    addon_slug: str,
    distinct_id: str,
    asset: Dict[str, Any] | None = None,
) -> None:
    def _send() -> None:
        a, cat_name, subcat_name = _parse_asset(asset)
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name="favourite_added",
            distinct_id=distinct_id,
            properties={
                "asset_id":    _safe_str((asset or {}).get("id", "")),
                "asset_name":  _safe_str(a.get("Title", a.get("title", "Unknown"))),
                "category":    cat_name,
                "sub_category": subcat_name,
                "host_app":    HOST_APP,
            },
        )
    _send_async(_send)


def send_session_start(
    *,
    license_server: str,
    addon_slug: str,
    addon_version: str,
    distinct_id: str,
    host_version: str = "",
    extra: Dict[str, Any] | None = None,
) -> None:
    def _send() -> None:
        props: Dict[str, Any] = {
            "host_app": HOST_APP,
            "host_version": host_version,
            "os": platform.system(),
            "addon_version": addon_version,
        }
        # Plan context (plan / is_premium / account_email / is_guest) so the dashboard can
        # compute plan distribution per stable user identity.
        if extra:
            props.update(extra)
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name="session_started",
            distinct_id=distinct_id,
            properties=props,
        )

    _send_async(_send)


def send_search_event(
    *,
    license_server: str,
    addon_slug: str,
    distinct_id: str,
    query: str,
    results_count: int,
    category: str,
    result_asset_names: list | None = None,
    result_asset_ids: list | None = None,
) -> None:
    def _send() -> None:
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name="search_performed",
            distinct_id=distinct_id,
            properties={
                "query":              _safe_str(query).lower().strip(),
                "results_count":      int(results_count or 0),
                "has_results":        int(results_count or 0) > 0,
                "category":           _safe_str(category),
                "result_asset_names": result_asset_names or [],
                "result_asset_ids":   [_safe_str(i) for i in (result_asset_ids or [])],
            },
        )

    _send_async(_send)


def send_download_event(
    *,
    license_server: str,
    addon_slug: str,
    addon_version: str,
    distinct_id: str,
    asset: Dict[str, Any] | None,
    file_entry: Dict[str, Any] | None,
    host_version: str = "",
) -> None:
    def _send() -> None:
        a, cat_name, subcat_name = _parse_asset(asset)
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name="asset_downloaded",
            distinct_id=distinct_id,
            properties={
                "asset_name": _safe_str(a.get("Title", a.get("title", "Unknown"))),
                "asset_id": _safe_str((asset or {}).get("id", "")),
                "category": cat_name,
                "sub_category": subcat_name,
                "format": _safe_str((file_entry or {}).get("fmt", "")),
                "resolution": _safe_str((file_entry or {}).get("res", "")),
                "os": platform.system(),
                "host_app": HOST_APP,
                "host_version": host_version,
                "addon_version": addon_version,
            },
        )

    _send_async(_send)


def send_import_event(
    *,
    license_server: str,
    addon_slug: str,
    distinct_id: str,
    asset: Dict[str, Any] | None,
    import_mode: str,
    success: bool,
    fmt: str,
) -> None:
    def _send() -> None:
        a, _, _ = _parse_asset(asset)
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name="asset_imported",
            distinct_id=distinct_id,
            properties={
                "asset_name": _safe_str(a.get("Title", a.get("title", "Unknown"))),
                "asset_id": _safe_str((asset or {}).get("id", "")),
                "import_mode": _safe_str(import_mode),
                "success": bool(success),
                "format": _safe_str(fmt),
                "host_app": HOST_APP,
            },
        )

    _send_async(_send)


def send_category_event(
    *,
    license_server: str,
    addon_slug: str,
    distinct_id: str,
    category_slug: str,
    sub_category: str = "",
) -> None:
    def _send() -> None:
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name="category_clicked",
            distinct_id=distinct_id,
            properties={
                "category": _safe_str(category_slug),
                "sub_category": _safe_str(sub_category),
            },
        )

    _send_async(_send)


def send_asset_viewed(
    *,
    license_server: str,
    addon_slug: str,
    distinct_id: str,
    asset: Dict[str, Any] | None,
    view_source: str = "popup",
) -> None:
    def _send() -> None:
        a, cat_name, subcat_name = _parse_asset(asset)
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name="asset_viewed",
            distinct_id=distinct_id,
            properties={
                "asset_name": _safe_str(a.get("Title", a.get("title", "Unknown"))),
                "asset_id": _safe_str((asset or {}).get("id", "")),
                "category": cat_name,
                "sub_category": subcat_name,
                "view_source": _safe_str(view_source),
                "host_app": HOST_APP,
            },
        )

    _send_async(_send)


def send_api_call_performance(
    *,
    license_server: str,
    addon_slug: str,
    distinct_id: str,
    endpoint: str,
    status: str,
    response_time_ms: int,
    http_status: int | None = None,
    error: str = "",
    sample_rate: float = 1.0,
) -> None:
    if not _should_sample(sample_rate):
        return

    def _send() -> None:
        props: Dict[str, Any] = {
            "endpoint": _safe_str(endpoint),
            "status": _safe_str(status),
            "response_time_ms": int(response_time_ms or 0),
            "host_app": HOST_APP,
        }
        if http_status is not None:
            props["http_status"] = int(http_status)
        if error:
            props["error"] = _safe_str(error)[:200]
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name="api_call_performance",
            distinct_id=distinct_id,
            properties=props,
        )

    _send_async(_send)


def send_asset_load_performance(
    *,
    license_server: str,
    addon_slug: str,
    distinct_id: str,
    source: str,
    load_time_ms: int,
    asset_count: int,
    sample_rate: float = 1.0,
) -> None:
    if not _should_sample(sample_rate):
        return

    def _send() -> None:
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name="asset_load_performance",
            distinct_id=distinct_id,
            properties={
                "source": _safe_str(source),
                "load_time_ms": int(load_time_ms or 0),
                "asset_count": int(asset_count or 0),
                "host_app": HOST_APP,
            },
        )

    _send_async(_send)


def send_download_performance(
    *,
    license_server: str,
    addon_slug: str,
    distinct_id: str,
    asset: Dict[str, Any] | None,
    status: str,
    file_size_bytes: int,
    download_time_ms: int,
    avg_speed_kbps: int,
    error: str = "",
    sample_rate: float = 0.5,
) -> None:
    if not _should_sample(sample_rate):
        return

    def _send() -> None:
        a, cat_name, subcat_name = _parse_asset(asset)
        props: Dict[str, Any] = {
            "status": _safe_str(status),
            "file_size_bytes": int(file_size_bytes or 0),
            "download_time_ms": int(download_time_ms or 0),
            "avg_speed_kbps": int(avg_speed_kbps or 0),
            "asset_name": _safe_str(a.get("Title", a.get("title", "Unknown"))),
            "asset_id": _safe_str((asset or {}).get("id", "")),
            "category": cat_name,
            "sub_category": subcat_name,
            "host_app": HOST_APP,
        }
        if error:
            props["error"] = _safe_str(error)[:200]
        _post_event(
            license_server=license_server,
            addon_slug=addon_slug,
            event_name="download_performance",
            distinct_id=distinct_id,
            properties=props,
        )

    _send_async(_send)

