"""
Agent Status SDK - HTTP client implementation.
"""

import time
from typing import Any, Dict, List, Optional

import httpx

from agent_status.models import Agent, AgentStatus, RunResult, Verdict


class AgentStatusError(Exception):
    """Base exception for Agent Status SDK errors."""

    def __init__(self, message: str, status_code: Optional[int] = None, details: Any = None):
        super().__init__(message)
        self.status_code = status_code
        self.details = details


class AgentStatusAuthError(AgentStatusError):
    """Authentication error."""

    pass


class AgentStatusNotFoundError(AgentStatusError):
    """Resource not found."""

    pass


class AgentStatusRateLimitError(AgentStatusError):
    """Rate limit exceeded."""

    pass


# Backward compatibility aliases
RoraError = AgentStatusError
RoraAuthError = AgentStatusAuthError
RoraNotFoundError = AgentStatusNotFoundError
RoraRateLimitError = AgentStatusRateLimitError


class AgentStatusClient:
    """
    HTTP client for the Agent Status API.

    Not intended for direct use - use the module-level functions instead:
        import agent_status
        agent_status.init(api_key="...")
        agent_status.register(...)
    """

    def __init__(
        self,
        api_key: str,
        base_url: str = "https://api.fabric.carmel.so",
        timeout: float = 60.0,
    ):
        self.api_key = api_key
        self.base_url = base_url.rstrip("/")
        self.timeout = timeout

        if api_key.startswith("fb_live_") or api_key.startswith("fb_test_"):
            auth_headers = {"X-API-Key": api_key}
        else:
            auth_headers = {"Authorization": f"Bearer {api_key}"}

        self._client = httpx.Client(
            base_url=self.base_url,
            timeout=timeout,
            headers={
                **auth_headers,
                "Content-Type": "application/json",
                "User-Agent": "agent-status-sdk/1.0.0",
            },
        )

    def _request(
        self,
        method: str,
        path: str,
        json: Optional[Dict] = None,
        params: Optional[Dict] = None,
    ) -> Dict:
        """Make an HTTP request and handle errors."""
        try:
            response = self._client.request(
                method=method,
                url=path,
                json=json,
                params=params,
            )
        except httpx.TimeoutException as e:
            raise AgentStatusError(f"Request timed out: {e}")
        except httpx.RequestError as e:
            raise AgentStatusError(f"Request failed: {e}")

        def safe_json():
            try:
                return response.json() if response.text else None
            except Exception:
                return None

        if response.status_code == 401:
            raise AgentStatusAuthError(
                "Invalid API key",
                status_code=401,
                details=safe_json(),
            )
        elif response.status_code == 404:
            raise AgentStatusNotFoundError(
                "Resource not found",
                status_code=404,
                details=safe_json(),
            )
        elif response.status_code == 429:
            raise AgentStatusRateLimitError(
                "Rate limit exceeded",
                status_code=429,
                details=safe_json(),
            )
        elif response.status_code >= 400:
            details = safe_json()
            detail = details.get("detail", "Unknown error") if details else "Unknown error"
            raise AgentStatusError(
                f"API error: {detail}",
                status_code=response.status_code,
                details=details,
            )

        try:
            return response.json()
        except Exception:
            raise AgentStatusError(
                "Invalid JSON response from API",
                status_code=response.status_code,
            )

    def register(
        self,
        endpoint: str,
        name: str,
        *,
        auth: Optional[Dict] = None,
        prompts: Optional[List[str]] = None,
        interval_minutes: int = 360,
        max_nodes_per_run: int = 5,
        geos: Optional[List[str]] = None,
        eval_type: str = "basic",
        gold_prompt_profile: str = "general",
        timeout_ms: int = 30000,
        streaming: bool = False,
        inject_geo_context: bool = False,
    ) -> Agent:
        """Register an agent for continuous monitoring."""
        payload = {
            "endpoint_url": endpoint,
            "name": name,
            "interval_minutes": interval_minutes,
            "max_nodes_per_run": max_nodes_per_run,
            "eval_type": eval_type,
            "gold_prompt_profile": gold_prompt_profile,
            "timeout_ms": timeout_ms,
            "streaming": streaming,
            "inject_geo_context": inject_geo_context,
            "schedule_type": "interval",
            "status": "active",
        }

        if auth:
            payload["auth"] = auth
        if prompts:
            payload["prompts"] = prompts
        if geos:
            payload["geos"] = geos

        data = self._request("POST", "/api/rora/agents", json=payload)
        return Agent(**data)

    def status(self, agent_id: str) -> AgentStatus:
        """Get current status of an agent."""
        data = self._request("GET", f"/api/rora/agents/{agent_id}/status")

        verdict_str = data.get("last_verdict", "UNKNOWN").upper()
        try:
            verdict = Verdict(verdict_str)
        except ValueError:
            verdict = Verdict.UNKNOWN

        return AgentStatus(
            agent_id=agent_id,
            verdict=verdict,
            uptime_24h=data.get("uptime_24h"),
            uptime_7d=data.get("uptime_7d"),
            latency_p50=data.get("latency_p50_ms") or data.get("latency_p50"),
            latency_p95=data.get("latency_p95_ms") or data.get("latency_p95"),
            pass_rate=data.get("pass_rate"),
            gold_pass_rate=data.get("gold_pass_rate"),
            last_checked=data.get("last_run_at"),
            total_checks=data.get("total_runs_24h", 0),
            by_region=data.get("by_region"),
        )

    def run(
        self,
        endpoint: str,
        prompts: List[str],
        *,
        auth: Optional[Dict] = None,
        max_nodes: int = 3,
        geos: Optional[List[str]] = None,
        timeout_ms: int = 30000,
        eval_type: str = "basic",
    ) -> RunResult:
        """Run a one-off validation."""
        payload = {
            "endpoint_url": endpoint,
            "prompts": prompts,
            "max_nodes": max_nodes,
            "timeout_ms": timeout_ms,
            "eval_type": eval_type,
        }

        if auth:
            payload["auth"] = auth
        if geos:
            payload["geos"] = geos

        submit_data = self._request("POST", "/api/rora/run", json=payload)
        decision_id = submit_data.get("decision_id")

        if not decision_id:
            raise AgentStatusError("No decision_id returned from run submission")

        max_wait = 120
        poll_interval = 2
        elapsed = 0

        while elapsed < max_wait:
            result_data = self._request("GET", f"/api/rora/runs/{decision_id}")

            status = result_data.get("status", "pending")
            if status == "completed":
                return self._parse_run_result(decision_id, result_data)
            elif status == "failed":
                raise AgentStatusError(
                    f"Run failed: {result_data.get('error', 'Unknown error')}",
                    details=result_data,
                )

            time.sleep(poll_interval)
            elapsed += poll_interval

        raise AgentStatusError(f"Run timed out after {max_wait} seconds", details={"decision_id": decision_id})

    def _parse_run_result(self, decision_id: str, data: Dict) -> RunResult:
        """Parse API response into RunResult model."""
        verdict_str = data.get("verdict", data.get("status", "UNKNOWN")).upper()
        try:
            verdict = Verdict(verdict_str)
        except ValueError:
            verdict = Verdict.UNKNOWN

        return RunResult(
            decision_id=decision_id,
            verdict=verdict,
            latency_p50=data.get("latency_p50_ms") or data.get("latency_p50"),
            latency_p95=data.get("latency_p95_ms") or data.get("latency_p95"),
            latency_p99=data.get("latency_p99_ms") or data.get("latency_p99"),
            ttfb_p50=data.get("ttfb_p50_ms"),
            ttfb_p95=data.get("ttfb_p95_ms"),
            pass_rate=data.get("pass_rate"),
            gold_pass_rate=data.get("gold_pass_rate"),
            total_probes=data.get("total_probes", 0),
            successful_probes=data.get("successful_probes", 0),
            failed_probes=data.get("failed_probes", 0),
            by_region=data.get("by_region"),
            probe_results=data.get("probe_results"),
            judge_result=data.get("judge_result"),
            tested_at=data.get("tested_at"),
        )

    def get_agent(self, agent_id: str) -> Agent:
        """Get an agent by ID."""
        data = self._request("GET", f"/api/rora/agents/{agent_id}")
        return Agent(**data)

    def list_agents(self) -> List[Agent]:
        """List all agents."""
        data = self._request("GET", "/api/rora/agents")
        agents_data = data.get("agents", data) if isinstance(data, dict) else data
        return [Agent(**a) for a in agents_data]

    def delete_agent(self, agent_id: str) -> bool:
        """Delete an agent."""
        self._request("DELETE", f"/api/rora/agents/{agent_id}")
        return True

    def __del__(self):
        """Close the HTTP client."""
        if hasattr(self, "_client"):
            self._client.close()


# Backward compatibility alias
RoraClient = AgentStatusClient
