"""Mock OpenTelemetry Collector for testing.

Provides HTTP endpoints that simulate OTel Collector behavior without requiring
a real collector instance. Used to test SDK telemetry export functionality.
"""

import json
import threading
from typing import Dict, List, Any
from flask import Flask, request, jsonify
import werkzeug.serving


class MockOTelCollector:
    """Mock OpenTelemetry Collector HTTP server.

    Provides /v1/metrics, /v1/logs, /v1/traces endpoints that:
    - Accept OTLP/HTTP requests
    - Return 200 OK
    - Store received telemetry for test assertions

    Thread-safe for concurrent requests from multiple test clients.
    """

    def __init__(self, host: str = "127.0.0.1", port: int = 0):
        """Initialize mock collector.

        Args:
            host: Bind address (default: 127.0.0.1)
            port: Bind port (0 = auto-assign available port)
        """
        self.host = host
        self.port = port
        self._actual_port: int = 0

        # Storage for received telemetry
        self._metrics: List[Dict[str, Any]] = []
        self._logs: List[Dict[str, Any]] = []
        self._traces: List[Dict[str, Any]] = []
        self._lock = threading.Lock()

        # Flask app and server
        self.app = Flask(__name__)
        self._server: Any = None
        self._thread: Any = None

        # Register routes
        self.app.add_url_rule("/v1/metrics", "metrics", self._handle_metrics, methods=["POST"])
        self.app.add_url_rule("/v1/logs", "logs", self._handle_logs, methods=["POST"])
        self.app.add_url_rule("/v1/traces", "traces", self._handle_traces, methods=["POST"])
        self.app.add_url_rule("/", "health", self._handle_health, methods=["GET"])

    def _handle_metrics(self):
        """Handle POST /v1/metrics requests."""
        try:
            data = request.get_json(force=True)
            with self._lock:
                self._metrics.append(data)
            return jsonify({"status": "success"}), 200
        except Exception as e:
            return jsonify({"error": str(e)}), 400

    def _handle_logs(self):
        """Handle POST /v1/logs requests."""
        try:
            data = request.get_json(force=True)
            with self._lock:
                self._logs.append(data)
            return jsonify({"status": "success"}), 200
        except Exception as e:
            return jsonify({"error": str(e)}), 400

    def _handle_traces(self):
        """Handle POST /v1/traces requests."""
        try:
            data = request.get_json(force=True)
            with self._lock:
                self._traces.append(data)
            return jsonify({"status": "success"}), 200
        except Exception as e:
            return jsonify({"error": str(e)}), 400

    def _handle_health(self):
        """Handle GET / health check requests."""
        return (
            jsonify(
                {
                    "status": "Server available",
                    "pipelines": {
                        "metrics": "healthy",
                        "logs": "healthy",
                        "traces": "healthy",
                    },
                }
            ),
            200,
        )

    def start(self) -> str:
        """Start mock collector server in background thread.

        Returns:
            Base URL of the collector (e.g., http://127.0.0.1:12345)
        """
        if self._thread and self._thread.is_alive():
            return self.url

        # Disable Flask request logging to reduce test noise
        import logging

        log = logging.getLogger("werkzeug")
        log.setLevel(logging.ERROR)

        # Create server
        self._server = werkzeug.serving.make_server(self.host, self.port, self.app, threaded=True)
        self._actual_port = self._server.port

        # Start server thread
        self._thread = threading.Thread(target=self._server.serve_forever, daemon=True)
        self._thread.start()

        return self.url

    def stop(self):
        """Stop mock collector server."""
        if self._server:
            self._server.shutdown()
        if self._thread:
            self._thread.join(timeout=2)

    @property
    def url(self) -> str:
        """Get base URL of collector."""
        return f"http://{self.host}:{self._actual_port}"

    def reset(self):
        """Clear all stored telemetry."""
        with self._lock:
            self._metrics.clear()
            self._logs.clear()
            self._traces.clear()

    def get_metrics(self) -> List[Dict[str, Any]]:
        """Get all received metrics (copy)."""
        with self._lock:
            return self._metrics.copy()

    def get_logs(self) -> List[Dict[str, Any]]:
        """Get all received logs (copy)."""
        with self._lock:
            return self._logs.copy()

    def get_traces(self) -> List[Dict[str, Any]]:
        """Get all received traces (copy)."""
        with self._lock:
            return self._traces.copy()

    def metrics_count(self) -> int:
        """Get count of received metric requests."""
        with self._lock:
            return len(self._metrics)

    def logs_count(self) -> int:
        """Get count of received log requests."""
        with self._lock:
            return len(self._logs)

    def traces_count(self) -> int:
        """Get count of received trace requests."""
        with self._lock:
            return len(self._traces)
