"""Telemetry Collector — Buffer and batch-send anonymous events to cloud.

Non-blocking, fire-and-forget. Events are buffered in-memory and flushed
every 60 seconds or when buffer hits 50 events. If the cloud endpoint
is unreachable, events are silently discarded.
"""

import asyncio
import json
import logging
import time
from datetime import datetime, timezone

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

# Buffer
_event_buffer: list[dict] = []
_flush_task: asyncio.Task | None = None
_platform: str = "unknown"

MAX_BUFFER_SIZE = 50
FLUSH_INTERVAL = 60  # seconds


def set_platform(platform: str):
    """Set the platform identifier (vscode/desktop/browser)."""
    global _platform
    _platform = platform


def track(event_type: str, category: str, properties: dict | None = None):
    """Track a telemetry event (non-blocking, buffered).

    Args:
        event_type: e.g., 'tool_called', 'memory_stored', 'error'
        category: e.g., 'tool_usage', 'sync', 'error'
        properties: optional dict of event properties (no PII!)
    """
    try:
        from soagila.config import get_settings
        settings = get_settings()
        if not settings.telemetry_enabled:
            return
    except Exception:
        return

    event = {
        "event_type": event_type[:50],
        "event_category": category[:20],
        "properties": properties or {},
        "platform": _platform,
        "extension_version": _get_version(),
        "timestamp": datetime.now(timezone.utc).isoformat(),
    }

    _event_buffer.append(event)

    # Auto-flush if buffer full
    if len(_event_buffer) >= MAX_BUFFER_SIZE:
        asyncio.create_task(_flush_async())


async def flush():
    """Flush buffered events to cloud endpoint."""
    await _flush_async()


async def _flush_async():
    """Send buffered events to cloud. Non-blocking, discards on failure."""
    global _event_buffer

    if not _event_buffer:
        return

    # Grab current buffer and reset
    events = _event_buffer[:MAX_BUFFER_SIZE]
    _event_buffer = _event_buffer[MAX_BUFFER_SIZE:]

    try:
        from soagila.config import get_settings
        settings = get_settings()
        if not settings.telemetry_enabled:
            return

        endpoint = f"{settings.telemetry_endpoint}/telemetry/events"

        payload = json.dumps({"events": events})

        try:
            import httpx
            async with httpx.AsyncClient(timeout=5.0) as client:
                await client.post(
                    endpoint,
                    content=payload,
                    headers={"Content-Type": "application/json"},
                )
        except ImportError:
            # httpx not available, try urllib (sync fallback)
            import urllib.request
            req = urllib.request.Request(
                endpoint,
                data=payload.encode(),
                headers={"Content-Type": "application/json"},
            )
            try:
                urllib.request.urlopen(req, timeout=5)
            except Exception:
                pass

        logger.debug(f"Telemetry flushed: {len(events)} events")
    except Exception:
        pass  # Never fail user operations


async def start_flush_timer():
    """Start periodic flush timer (call once on startup)."""
    global _flush_task
    if _flush_task and not _flush_task.done():
        return
    _flush_task = asyncio.create_task(_flush_loop())


async def _flush_loop():
    """Background loop: flush events periodically."""
    while True:
        try:
            await asyncio.sleep(FLUSH_INTERVAL)
            await _flush_async()
        except asyncio.CancelledError:
            # Final flush on cancellation
            await _flush_async()
            raise
        except Exception:
            pass


async def stop_flush_timer():
    """Stop the flush timer and do a final flush."""
    global _flush_task
    if _flush_task and not _flush_task.done():
        _flush_task.cancel()
        try:
            await _flush_task
        except asyncio.CancelledError:
            pass
    # Final flush
    await _flush_async()


def _get_version() -> str:
    try:
        from soagila.config import get_settings
        return get_settings().app_version
    except Exception:
        return "unknown"


def get_buffer_size() -> int:
    """Get current buffer size (for diagnostics)."""
    return len(_event_buffer)
