"""Telemetry client for sending events to the platform."""

from __future__ import annotations

import atexit
import logging
import queue
import random
import threading
import time
from typing import Any

from rotalabs._telemetry.config import get_config, is_enabled
from rotalabs._telemetry.events import TelemetryEvent

logger = logging.getLogger("rotalabs.telemetry")

# Global state
_event_queue: queue.Queue[TelemetryEvent] = queue.Queue(maxsize=1000)
_worker_thread: threading.Thread | None = None
_shutdown_event = threading.Event()
_started = False


def _should_sample() -> bool:
    """Check if this event should be sampled."""
    config = get_config()
    if config is None:
        return False
    if config.sample_rate >= 1.0:
        return True
    return random.random() < config.sample_rate


def _send_batch(events: list[TelemetryEvent]) -> bool:
    """Send a batch of events to the platform."""
    config = get_config()
    if config is None or not events:
        return False

    try:
        import httpx

        payload = {
            "events": [e.to_dict() for e in events],
        }

        with httpx.Client(timeout=config.timeout) as client:
            response = client.post(
                f"{config.base_url}/v1/telemetry/ingest",
                json=payload,
                headers={
                    "Authorization": f"Bearer {config.api_key}",
                    "Content-Type": "application/json",
                    "User-Agent": f"rotalabs-telemetry/{events[0].sdk_version}",
                },
            )
            if response.status_code == 429:
                # Rate limited, back off
                retry_after = response.headers.get("Retry-After", "60")
                logger.warning(f"Telemetry rate limited, retry after {retry_after}s")
                return False
            response.raise_for_status()
            return True

    except ImportError:
        logger.warning("httpx not installed, telemetry disabled")
        return False
    except Exception as e:
        logger.debug(f"Failed to send telemetry: {e}")
        return False


def _worker_loop() -> None:
    """Background worker that sends batched events."""
    config = get_config()
    if config is None:
        return

    batch: list[TelemetryEvent] = []
    last_flush = time.time()

    while not _shutdown_event.is_set():
        try:
            # Wait for events with timeout
            try:
                event = _event_queue.get(timeout=1.0)
                batch.append(event)
            except queue.Empty:
                pass

            # Check if we should flush
            now = time.time()
            should_flush = (
                len(batch) >= config.batch_size
                or (batch and now - last_flush >= config.flush_interval)
            )

            if should_flush and batch:
                _send_batch(batch)
                batch = []
                last_flush = now

        except Exception as e:
            logger.debug(f"Telemetry worker error: {e}")

    # Flush remaining events on shutdown
    if batch:
        _send_batch(batch)


def _ensure_worker_started() -> None:
    """Ensure the background worker is running."""
    global _worker_thread, _started

    if _started:
        return

    _started = True
    _shutdown_event.clear()
    _worker_thread = threading.Thread(target=_worker_loop, daemon=True)
    _worker_thread.start()

    # Register shutdown handler
    atexit.register(shutdown)


def report_event(
    event_type: str,
    data: dict[str, Any],
) -> None:
    """Report a telemetry event (non-blocking).

    This function is safe to call even if telemetry is disabled.
    Events are queued and sent in batches by a background thread.

    Args:
        event_type: The type of event (e.g., "steer.vector.applied").
        data: Event data to include.
    """
    if not is_enabled():
        return

    if not _should_sample():
        return

    config = get_config()
    if config is None:
        return

    # Create event
    event = TelemetryEvent(
        event_type=event_type,
        data=data,
        package_name=config.package_name,
        package_version=config.package_version,
    )

    # Add to queue (non-blocking)
    try:
        _event_queue.put_nowait(event)
    except queue.Full:
        logger.debug("Telemetry queue full, dropping event")
        return

    # Start worker if needed
    _ensure_worker_started()


def flush() -> None:
    """Flush all pending events immediately."""
    if not is_enabled():
        return

    events: list[TelemetryEvent] = []
    while True:
        try:
            event = _event_queue.get_nowait()
            events.append(event)
        except queue.Empty:
            break

    if events:
        _send_batch(events)


def shutdown() -> None:
    """Shutdown the telemetry client, flushing remaining events."""
    global _started

    if not _started:
        return

    _shutdown_event.set()

    if _worker_thread is not None:
        _worker_thread.join(timeout=5.0)

    _started = False
