"""
JSONFIRST Python SDK v1.0
Universal Intent Protocol
https://jsonfirst.com/developers

Install: pip install httpx
Usage:
    from jsonfirst import JSONFIRSTClient
    client = JSONFIRSTClient(api_key="your_key")
    result = client.convert("Send email to Marie about Thursday meeting")
    print(result["jdons"][0]["action"]["normalized"])  # "send"
"""

import httpx
from typing import Optional, Literal, List

ExecutionMode = Literal[
    "ANTI_CREDIT_WASTE_V2",   # 0 LLM calls — pure local parsing (default)
    "EXPRESS_ROUTE",          # Ultra-low latency, optimized for real-time
    "STRICT_PROTOCOL",        # Temperature=0, maximum validation
    "PERFORMANCE_MAX",        # Deep analysis, full confidence scoring
]


class JDONAction:
    def __init__(self, data: dict):
        self.raw: str = data.get("raw", "")
        self.normalized: str = data.get("normalized", "")

    def __repr__(self):
        return f"JDONAction(raw={self.raw!r}, normalized={self.normalized!r})"


class JDON:
    """A single JSON Data Object of Nature — the atomic unit of JSONFIRST."""
    def __init__(self, data: dict):
        self.jdon_id: str = data.get("jdon_id", "")
        self.confidence: float = data.get("confidence", 0.0)
        self.action = JDONAction(data.get("action", {}))
        self.object: dict = data.get("object", {})
        self.domain: dict = data.get("domain", {})
        self.constraints: dict = data.get("constraints", {})
        self._raw = data

    def to_dict(self) -> dict:
        return self._raw

    def __repr__(self):
        return (
            f"JDON(id={self.jdon_id[:12]}…, "
            f"action={self.action.normalized!r}, "
            f"confidence={self.confidence:.2f})"
        )


class JSONFIRSTResponse:
    """Full response from the JSONFIRST API."""
    def __init__(self, data: dict):
        self._raw = data
        self.spec: str = data.get("spec", "JSONFIRST")
        self.version: str = data.get("version", "")
        self.jdons: List[JDON] = [JDON(j) for j in data.get("jdons", [])]
        self.execution: dict = data.get("execution", {})
        self.execution_mode: dict = data.get("execution_mode", {})
        self.input: dict = data.get("input", {})

    @property
    def first_jdon(self) -> Optional[JDON]:
        """The primary JDON extracted from the intent."""
        return self.jdons[0] if self.jdons else None

    @property
    def is_executable(self) -> bool:
        return self.execution.get("executable", False)

    @property
    def mode(self) -> str:
        return self.execution_mode.get("name", "")

    def to_dict(self) -> dict:
        return self._raw

    def __repr__(self):
        return (
            f"JSONFIRSTResponse("
            f"jdons={len(self.jdons)}, "
            f"mode={self.mode!r}, "
            f"executable={self.is_executable})"
        )


class JSONFIRSTError(Exception):
    """Raised when the JSONFIRST API returns an error."""
    def __init__(self, status_code: int, message: str):
        self.status_code = status_code
        super().__init__(f"JSONFIRST API error {status_code}: {message}")


class JSONFIRSTClient:
    """
    Official Python SDK for the JSONFIRST Universal Intent Protocol v3.0.

    Converts natural language intentions into structured, executable JSON objects (JDONs).
    Supports 4 execution modes including ANTI_CREDIT_WASTE_V2 (0 LLM calls).

    Args:
        api_key: Your JSONFIRST API key (from https://jsonfirst.com/app)
        base_url: Base URL (default: https://jsonfirst.com)
        timeout: Request timeout in seconds (default: 30)

    Example:
        with JSONFIRSTClient(api_key="jf_xxxx") as client:
            result = client.convert("Deploy backend to production")
            jdon = result.first_jdon
            print(jdon.action.normalized)  # "deploy"
            print(jdon.confidence)         # 0.95
    """

    BASE_URL = "https://jsonfirst.com"
    SDK_VERSION = "1.0.0"

    def __init__(
        self,
        api_key: str,
        base_url: str = BASE_URL,
        timeout: int = 30,
    ):
        self.api_key = api_key
        self.base_url = base_url.rstrip("/")
        self._client = httpx.Client(
            headers={
                "Authorization": f"Bearer {api_key}",
                "Content-Type": "application/json",
                "X-SDK-Version": f"python/{self.SDK_VERSION}",
                "User-Agent": f"jsonfirst-python/{self.SDK_VERSION}",
            },
            timeout=timeout,
        )

    def convert(
        self,
        text: str,
        mode: ExecutionMode = "ANTI_CREDIT_WASTE_V2",
        language: str = "fr",
    ) -> JSONFIRSTResponse:
        """
        Convert natural language intent to a structured JDON object.

        This is the core method of the JSONFIRST protocol.
        By default, uses ANTI_CREDIT_WASTE_V2 mode — zero LLM calls,
        pure deterministic parsing. No API credit consumed on your LLM provider.

        Args:
            text: The natural language intent to convert.
            mode: Execution mode.
                - ANTI_CREDIT_WASTE_V2: 0 LLM calls (fastest, cheapest)
                - EXPRESS_ROUTE: Ultra-low latency (<20ms target)
                - STRICT_PROTOCOL: Maximum validation, temperature=0
                - PERFORMANCE_MAX: Full analysis, highest confidence
            language: Language hint ("fr" or "en"). Default: "fr".

        Returns:
            JSONFIRSTResponse with typed JDON objects.

        Raises:
            JSONFIRSTError: If the API returns an error.

        Example:
            result = client.convert("Send email to Marie about Thursday meeting")
            jdon = result.first_jdon
            # jdon.action.normalized → "send"
            # jdon.domain.primary → "communication"
        """
        response = self._client.post(
            f"{self.base_url}/api/jsonfirst",
            json={"text": text, "mode": mode, "language": language},
        )
        if not response.is_success:
            raise JSONFIRSTError(response.status_code, response.text)
        return JSONFIRSTResponse(response.json())

    def convert_strict(self, text: str, language: str = "fr") -> JSONFIRSTResponse:
        """Convert with STRICT_PROTOCOL mode (temperature=0, maximum validation)."""
        return self.convert(text, mode="STRICT_PROTOCOL", language=language)

    def convert_fast(self, text: str, language: str = "fr") -> JSONFIRSTResponse:
        """Convert with EXPRESS_ROUTE mode (optimized for production pipelines)."""
        return self.convert(text, mode="EXPRESS_ROUTE", language=language)

    def get_jdon(self, text: str, mode: ExecutionMode = "ANTI_CREDIT_WASTE_V2") -> Optional[JDON]:
        """
        Convenience method: returns the first JDON directly.

        Example:
            jdon = client.get_jdon("Create a support ticket for API access")
            print(jdon.action.normalized)   # "create"
            print(jdon.constraints)         # {"subject": "API access", "type": "support"}
        """
        result = self.convert(text, mode=mode)
        return result.first_jdon

    def close(self):
        """Close the underlying HTTP client."""
        self._client.close()

    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.close()


# ── Quick usage example ───────────────────────────────────────────────────────
if __name__ == "__main__":
    # Replace with your API key from https://jsonfirst.com/app
    API_KEY = "your_jsonfirst_api_key"

    with JSONFIRSTClient(api_key=API_KEY) as client:
        # Basic conversion (0 LLM calls)
        result = client.convert("Send email to Marie to confirm Thursday meeting at 2pm")
        jdon = result.first_jdon
        print(f"Action: {jdon.action.normalized}")
        print(f"Confidence: {jdon.confidence:.0%}")
        print(f"Mode: {result.mode}")

        # Strict mode for high-stakes decisions
        result_strict = client.convert_strict("Deploy backend to production and notify team")
        print(f"Strict result: {result_strict.first_jdon}")
