"""Platform telemetry reporter — fire-and-forget event posting.

Sends routing decision telemetry to the Robot Resources platform
for product health monitoring and cost savings validation.
Follows the same patterns as OutcomeRecorder: lazy singleton,
async fire-and-forget, graceful degradation.
"""

from __future__ import annotations

import json
import os
from pathlib import Path

import httpx
import structlog

logger = structlog.get_logger()

_DEFAULT_CONFIG_PATH = Path.home() / ".robot-resources" / "config.json"
_DEFAULT_PLATFORM_URL = "https://api.robotresources.ai"

# Singleton state
_reporter: TelemetryReporter | None = None


class TelemetryReporter:
    """Posts telemetry events to the Robot Resources platform.

    Reads API key from ``~/.robot-resources/config.json`` on init.
    If no key is found, the reporter disables itself (no-op).

    Usage::

        reporter = TelemetryReporter()
        event = reporter.build_event(
            selected_model="gemini-2.5-flash",
            provider="google",
            task_type="simple_qa",
            cost_actual=0.001,
            cost_baseline=0.01,
            savings_percent=90.0,
            cost_saved=0.009,
            latency_ms=150,
            input_tokens=100,
            output_tokens=50,
        )
        await reporter.areport_safe(event)
    """

    def __init__(self, config_path: Path | None = None) -> None:
        self._config_path = config_path or _DEFAULT_CONFIG_PATH
        self.api_key: str | None = None
        self.platform_url: str = _DEFAULT_PLATFORM_URL
        self.enabled: bool = False
        self._client: httpx.AsyncClient = httpx.AsyncClient(timeout=5.0)
        self._warned: bool = False

        self._load_config()

        # Environment-level opt-out overrides config
        if os.environ.get("RR_TELEMETRY") == "off":
            self.enabled = False

    def _load_config(self) -> None:
        """Read API key and platform URL from config file."""
        try:
            raw = self._config_path.read_text(encoding="utf-8")
            config = json.loads(raw)
        except (FileNotFoundError, OSError):
            if not self._warned:
                logger.info("telemetry_no_config", path=str(self._config_path))
                self._warned = True
            return
        except json.JSONDecodeError:
            logger.warning("telemetry_invalid_config", path=str(self._config_path))
            return

        key = config.get("api_key", "")
        if not key:
            return

        self.api_key = key
        self.enabled = True

        # Config-level opt-out
        if config.get("telemetry", True) is False:
            self.enabled = False
            logger.info("telemetry_opt_out_config", path=str(self._config_path))
            return

        custom_url = config.get("platform_url")
        if custom_url:
            self.platform_url = custom_url

        logger.info("telemetry_enabled", platform_url=self.platform_url)

    # ------------------------------------------------------------------
    # Event building
    # ------------------------------------------------------------------

    def build_event(
        self,
        *,
        selected_model: str,
        provider: str,
        task_type: str,
        cost_actual: float,
        cost_baseline: float,
        savings_percent: float,
        cost_saved: float,
        latency_ms: int,
        input_tokens: int,
        output_tokens: int,
        savings_mode: str = "cost",
    ) -> dict:
        """Build a telemetry event dict matching the platform schema."""
        return {
            "product": "router",
            "event_type": "route_completed",
            "payload": {
                "selectedModel": selected_model,
                "provider": provider,
                "taskType": task_type,
                "costPerRequest": cost_actual,
                "baselineCost": cost_baseline,
                "savingsPercent": savings_percent,
                "savingsUsd": cost_saved,
                "routingTimeMs": latency_ms,
                "estimatedTokens": input_tokens + output_tokens,
                "savingsMode": savings_mode,
            },
        }

    # ------------------------------------------------------------------
    # HTTP posting
    # ------------------------------------------------------------------

    async def areport(self, event: dict) -> None:
        """Post a telemetry event to the platform. May raise on failure."""
        url = f"{self.platform_url}/v1/telemetry"
        response = await self._client.post(
            url,
            json=event,
            headers={"Authorization": f"Bearer {self.api_key}"},
        )
        response.raise_for_status()

    async def areport_safe(self, event: dict) -> None:
        """Fire-and-forget telemetry that never raises.

        Intended for use in request handlers where telemetry must not
        interfere with response delivery. Errors are logged and swallowed.
        """
        if not self.enabled:
            return
        try:
            await self.areport(event)
        except Exception:
            logger.warning("telemetry_report_failed", exc_info=True)


def get_telemetry_reporter() -> TelemetryReporter:
    """Get the telemetry reporter singleton, initializing on first call.

    Always returns a TelemetryReporter instance (never None).
    If config is missing, the reporter is disabled (no-op).
    """
    global _reporter  # noqa: PLW0603
    if _reporter is not None:
        return _reporter
    _reporter = TelemetryReporter()
    return _reporter
