"""
LangSmith platform integration for releaseops analytics.

Implements TracePlatform protocol using LangSmith REST API.
Uses httpx (optional dependency) — no hard dependency on langsmith SDK.
"""

from __future__ import annotations

import logging
import os
from typing import Any, Dict, List, Optional, Tuple

logger = logging.getLogger(__name__)

LANGSMITH_API_BASE = "https://api.smith.langchain.com"


class LangSmithPlatform:
    """
    LangSmith trace platform using REST API.

    Queries LangSmith for traces tagged with releaseops metadata.
    Requires httpx (install with: pip install llmhq-releaseops[langsmith]).
    """

    def __init__(
        self,
        api_key: Optional[str] = None,
        project_name: Optional[str] = None,
        api_base: Optional[str] = None,
    ) -> None:
        self._api_key = api_key or os.environ.get("LANGSMITH_API_KEY", "")
        self._project_name = project_name or os.environ.get("LANGSMITH_PROJECT", "default")
        self._api_base = api_base or os.environ.get("LANGSMITH_ENDPOINT", LANGSMITH_API_BASE)

    def _get_client(self):
        """Lazy-import httpx and return a configured client."""
        try:
            import httpx
        except ImportError:
            raise ImportError(
                "httpx is required for LangSmith integration. "
                "Install with: pip install llmhq-releaseops[langsmith]"
            )
        return httpx.Client(
            base_url=self._api_base,
            headers={"x-api-key": self._api_key},
            timeout=30.0,
        )

    def query_traces(
        self,
        filter: Dict[str, Any],
        limit: int = 100,
        time_range: Optional[Tuple[str, str]] = None,
    ) -> List[Dict[str, Any]]:
        """Query traces from LangSmith matching filter criteria."""
        client = self._get_client()
        try:
            params: Dict[str, Any] = {
                "limit": limit,
            }

            # Build filter for releaseops metadata
            filter_parts = []
            for key, value in filter.items():
                filter_parts.append(f'eq(metadata.releaseops.{key}, "{value}")')

            if filter_parts:
                params["filter"] = " and ".join(filter_parts)

            if time_range:
                params["start_time"] = time_range[0]
                params["end_time"] = time_range[1]

            response = client.get(
                f"/api/v1/runs",
                params={
                    "project_name": self._project_name,
                    **params,
                },
            )
            response.raise_for_status()
            runs = response.json()

            # Normalize to trace format
            return [self._normalize_run(run) for run in runs if isinstance(run, dict)]

        except Exception as e:
            logger.error(f"LangSmith query failed: {e}")
            raise
        finally:
            client.close()

    def get_trace(self, trace_id: str) -> Dict[str, Any]:
        """Get a single trace/run from LangSmith."""
        client = self._get_client()
        try:
            response = client.get(f"/api/v1/runs/{trace_id}")
            response.raise_for_status()
            return self._normalize_run(response.json())
        except Exception as e:
            logger.error(f"LangSmith get_trace failed: {e}")
            raise
        finally:
            client.close()

    def test_connection(self) -> bool:
        """Test API key and connectivity."""
        if not self._api_key:
            return False
        client = self._get_client()
        try:
            response = client.get("/api/v1/info")
            return response.status_code == 200
        except Exception:
            return False
        finally:
            client.close()

    def get_platform_name(self) -> str:
        return "langsmith"

    def _normalize_run(self, run: Dict[str, Any]) -> Dict[str, Any]:
        """Normalize LangSmith run to common trace format."""
        metadata = run.get("extra", {}).get("metadata", {})

        # Extract timing
        start_time = run.get("start_time", "")
        end_time = run.get("end_time", "")
        latency_ms = None
        if start_time and end_time:
            try:
                from datetime import datetime
                start = datetime.fromisoformat(start_time.replace("Z", "+00:00"))
                end = datetime.fromisoformat(end_time.replace("Z", "+00:00"))
                latency_ms = (end - start).total_seconds() * 1000
            except (ValueError, TypeError):
                pass

        # Extract tokens
        token_usage = run.get("total_tokens") or run.get("prompt_tokens", 0) + run.get("completion_tokens", 0)

        return {
            "trace_id": run.get("id", run.get("run_id", "")),
            "metadata": metadata,
            "latency_ms": latency_ms,
            "total_tokens": token_usage,
            "status": run.get("status", ""),
            "error": run.get("error"),
            "output": run.get("outputs"),
            "tool_calls": run.get("tool_calls", []),
            "timestamp": start_time,
            "bundle_id": metadata.get("releaseops.bundle_id", ""),
            "bundle_version": metadata.get("releaseops.bundle_version", ""),
            "environment": metadata.get("releaseops.environment", ""),
        }
