"""
Local file-based telemetry engine (free tier).

Exports telemetry data to JSONL files with buffering and auto-flush.
"""

import json
import time
from pathlib import Path
from typing import Any, Dict, List

from .base import TelemetryEngine
from .exporters.context import ContextExporter


class LocalTelemetryEngine(TelemetryEngine):
    """
    Local file-based telemetry engine (free tier).

    Exports to JSONL files with configurable buffering and auto-flush.
    """

    def __init__(
        self, output_dir: str = "./telemetry", buffer_size: int = 1000, flush_interval: float = 5.0
    ):
        self.output_dir = Path(output_dir)
        self.output_dir.mkdir(exist_ok=True, parents=True)

        # Separate files for different event types
        self.context_file = self.output_dir / "context_snapshots.jsonl"
        self.thread_file = self.output_dir / "provider_threads.jsonl"
        self.component_file = self.output_dir / "component_changes.jsonl"
        self.scaffold_file = self.output_dir / "scaffold_changes.jsonl"

        # Buffering
        self.buffer_size = buffer_size
        self.flush_interval = flush_interval
        self._buffers = {"context": [], "thread": [], "component": [], "scaffold": []}
        self._last_flush = time.time()

    def export_context_snapshot(self, context, phase: str, metadata: Dict):
        """Export context snapshot with PACT structure analysis."""
        event = {
            "timestamp": time.time_ns(),
            "type": "context_snapshot",
            "phase": phase,
            "episode": getattr(context, "current_episode", 0),
            "metadata": metadata,
            "pact_structure": ContextExporter.analyze_pact_structure(context),
            "pact_tree": context.model_dump() if hasattr(context, "model_dump") else {},
        }
        self._append_to_buffer("context", event, self.context_file)

    def export_provider_thread(self, thread, phase: str, metadata: Dict):
        """Export provider thread."""
        event = {
            "timestamp": time.time_ns(),
            "type": "provider_thread",
            "phase": phase,
            "metadata": metadata,
            "thread": thread.model_dump() if hasattr(thread, "model_dump") else {},
        }
        self._append_to_buffer("thread", event, self.thread_file)

    def export_component_change(self, operation: str, component, metadata: Dict):
        """Export component change (insert/update/delete)."""
        event = {
            "timestamp": time.time_ns(),
            "type": "component_change",
            "operation": operation,
            "component_type": type(component).__name__,
            "component_id": getattr(component, "id", "unknown"),
            "metadata": metadata,
            "component": component.model_dump() if hasattr(component, "model_dump") else {},
        }
        self._append_to_buffer("component", event, self.component_file)

    def export_scaffold_change(
        self, scaffold_id: str, old_state: Dict, new_state: Dict, metadata: Dict
    ):
        """Export scaffold state change."""
        event = {
            "timestamp": time.time_ns(),
            "type": "scaffold_change",
            "scaffold_id": scaffold_id,
            "old_state": old_state,
            "new_state": new_state,
            "metadata": metadata,
        }
        self._append_to_buffer("scaffold", event, self.scaffold_file)

    def _append_to_buffer(self, buffer_name: str, event: Dict, filepath: Path):
        """Append event to buffer and auto-flush if needed."""
        self._buffers[buffer_name].append(event)

        # Check if we need to flush (by size or time)
        if len(self._buffers[buffer_name]) >= self.buffer_size:
            self._flush_buffer(buffer_name, filepath)
        elif time.time() - self._last_flush >= self.flush_interval:
            self.flush()

    def _flush_buffer(self, buffer_name: str, filepath: Path):
        """Flush specific buffer to file."""
        if not self._buffers[buffer_name]:
            return

        with open(filepath, "a") as f:
            for event in self._buffers[buffer_name]:
                f.write(json.dumps(event) + "\n")

        self._buffers[buffer_name].clear()
        self._last_flush = time.time()

    def flush(self):
        """Flush all buffers."""
        self._flush_buffer("context", self.context_file)
        self._flush_buffer("thread", self.thread_file)
        self._flush_buffer("component", self.component_file)
        self._flush_buffer("scaffold", self.scaffold_file)
