"""
Sturna Python SDK
===================
Submit intents to Sturna's 81-agent engine from Python.

Quick start:
    pip install requests          # only dependency

    from sturna import Sturna

    client = Sturna(api_key="octo_...")   # or omit for free/anonymous tier
    result = client.intent("Design a REST API for user management")

    print(result["selected_agent"]["name"])   # e.g. "InsForge Engineer"
    print(result["result"])                   # winning agent's full output
"""

__version__ = "0.1.0"

import json


class SturnaError(Exception):
    """Raised when the Sturna API returns an error."""
    def __init__(self, message, status_code=None, data=None):
        super().__init__(message)
        self.status_code = status_code
        self.data = data


class Sturna:
    """
    Sturna client.

    Args:
        api_key:  Your API key (octo_...). Get one free at
                  https://app.sturna.ai
        base_url: Override the API base URL (default: production).

    Examples:
        # Anonymous (free tier, no key needed):
        client = Sturna()

        # Authenticated (tracked usage + higher limits):
        client = Sturna(api_key="octo_a1b2c3...")

        # Register and auto-set key:
        client = Sturna()
        client.register("you@example.com")   # sets client.api_key automatically
    """

    BASE_URL = "https://app.sturna.ai"

    def __init__(self, api_key=None, base_url=None):
        self.api_key = api_key
        self.base_url = (base_url or self.BASE_URL).rstrip("/")
        self._session = None

    def _get_session(self):
        """Lazy-load requests session."""
        if self._session is None:
            try:
                import requests
            except ImportError:
                raise ImportError(
                    "requests is required: pip install requests"
                )
            self._session = requests.Session()
            self._session.headers.update({"Content-Type": "application/json"})
        # Always sync the api_key header
        if self.api_key:
            self._session.headers["X-Api-Key"] = self.api_key
        elif "X-Api-Key" in self._session.headers:
            del self._session.headers["X-Api-Key"]
        return self._session

    def _request(self, method, path, body=None, params=None):
        """Make an authenticated API request."""
        session = self._get_session()
        url = f"{self.base_url}{path}"
        kwargs = {"params": params}
        if body is not None:
            kwargs["data"] = json.dumps(body)
        response = session.request(method, url, timeout=60, **kwargs)
        try:
            data = response.json()
        except Exception:
            data = {"message": response.text}
        if not response.ok:
            raise SturnaError(
                data.get("message", f"HTTP {response.status_code}"),
                status_code=response.status_code,
                data=data,
            )
        return data

    # -------------------------------------------------------------------------
    # Auth
    # -------------------------------------------------------------------------

    def register(self, email):
        """
        Register an email address and get a free API key.
        Idempotent — same email always returns the same key.
        Auto-sets self.api_key on success.

        Args:
            email: Your email address.

        Returns:
            dict with api_key, tier, daily_limit, upgrade_url.

        Example:
            client = Sturna()
            data = client.register("you@example.com")
            print(data["api_key"])   # octo_a1b2c3...
        """
        data = self._request("POST", "/api/register", {"email": email})
        if data.get("api_key"):
            self.api_key = data["api_key"]
        return data

    def me(self):
        """
        Get current tier and usage stats for the current API key.
        Requires self.api_key to be set.

        Returns:
            dict with email, tier, usage (requests_today or requests_month), etc.

        Example:
            info = client.me()
            print(info["tier"])           # "free" or "pro"
            print(info["usage"])          # usage dict
        """
        return self._request("GET", "/api/me")

    # -------------------------------------------------------------------------
    # Core
    # -------------------------------------------------------------------------

    def intent(self, text, context=None):
        """
        Submit an intent to the 81-agent engine.
        All agents evaluate it simultaneously; the winner is returned.

        Args:
            text:    What you want to build or solve (max 2000 chars).
            context: Optional dict with stack hints, e.g. {"stack": "Node.js"}.

        Returns:
            dict with selected_agent, proposals, result, processing_time_ms,
            intent_id, memory_hits.

        Example:
            result = client.intent(
                "Design a REST API for user authentication with JWT",
                context={"stack": "Node.js"}
            )
            agent = result["selected_agent"]
            print(f"Winner: {agent['emoji']} {agent['name']} (score: {agent['score']:.4f})")
            print(f"Result: {result['result'][:200]}...")
            print(f"{len(result['proposals'])} agents competed in {result['processing_time_ms']}ms")
        """
        return self._request("POST", "/api/intent", {
            "text": text,
            "context": context or {},
        })

    def agents(self):
        """
        List all 81 available agent types.

        Returns:
            dict with agents list, each containing type, name, emoji,
            description, keywords, base_cost.
        """
        return self._request("GET", "/api/agents")

    def intents(self, limit=20):
        """
        List recent intents with their proposals.

        Args:
            limit: Max number of intents to return (default: 20, max: 100).

        Returns:
            dict with intents list and count.
        """
        return self._request("GET", "/api/intents", params={"limit": limit})

    def memory(self, query):
        """
        Query shared agent memory for past execution results.

        Args:
            query: Search text (e.g. "authentication").

        Returns:
            dict with results list and count.
        """
        return self._request("GET", "/api/memory", params={"q": query})

    def stats(self):
        """
        Get engine statistics: total intents, proposals, per-agent win rates.

        Returns:
            dict with stats and agents.
        """
        return self._request("GET", "/api/stats")

    # -------------------------------------------------------------------------
    # Deploy (Pro)
    # -------------------------------------------------------------------------

    def deploy(self, intent_id):
        """
        Deploy a completed intent's winning output as a shareable URL.
        Requires Pro tier API key.

        Args:
            intent_id: The intent ID from a previous intent() call.

        Returns:
            dict with deploy_url, deploy_token, deploy_type, expires_at.

        Example:
            result = client.intent("Write a technical spec for a payments API")
            deploy = client.deploy(result["intent_id"])
            print(deploy["deploy_url"])   # https://app.sturna.ai/d/abc123
        """
        return self._request("POST", f"/api/intents/{intent_id}/deploy")

    def deployment_status(self, intent_id):
        """
        Check if an intent has an active deployment.

        Args:
            intent_id: The intent ID to check.

        Returns:
            dict with deployed (bool), and if True: deploy_url, expires_at.
        """
        return self._request("GET", f"/api/intents/{intent_id}/deployment")

    # -------------------------------------------------------------------------
    # Async (requires httpx: pip install httpx)
    # -------------------------------------------------------------------------

    async def intent_async(self, text, context=None):
        """
        Async version of intent(). Requires httpx: pip install httpx

        Args:
            text:    The intent text (max 2000 chars).
            context: Optional dict with stack hints.

        Returns:
            Same as intent().

        Example:
            import asyncio
            from sturna import Sturna

            async def main():
                client = Sturna(api_key="octo_...")
                result = await client.intent_async("Build a rate limiter in Redis")
                print(result["selected_agent"]["name"])

            asyncio.run(main())
        """
        try:
            import httpx
        except ImportError:
            raise ImportError(
                "httpx is required for async: pip install httpx"
            )

        headers = {"Content-Type": "application/json"}
        if self.api_key:
            headers["X-Api-Key"] = self.api_key

        async with httpx.AsyncClient(timeout=60.0) as client:
            response = await client.post(
                f"{self.base_url}/api/intent",
                json={"text": text, "context": context or {}},
                headers=headers,
            )
            try:
                data = response.json()
            except Exception:
                data = {"message": response.text}
            if not response.is_success:
                raise SturnaError(
                    data.get("message", f"HTTP {response.status_code}"),
                    status_code=response.status_code,
                    data=data,
                )
            return data


# ---------------------------------------------------------------------------
# CLI helper (python sturna.py "your intent here")
# ---------------------------------------------------------------------------
if __name__ == "__main__":
    import sys
    import os

    if len(sys.argv) < 2:
        print("Usage: python sturna.py 'your intent here'")
        print("       STURNA_API_KEY=octo_... python sturna.py 'your intent here'")
        sys.exit(1)

    text = " ".join(sys.argv[1:])
    api_key = os.environ.get("STURNA_API_KEY")

    client = Sturna(api_key=api_key)
    print(f"Submitting intent: {text[:80]}...")

    try:
        result = client.intent(text)
        agent = result["selected_agent"]
        print(f"\n Winner: {agent.get('emoji', '')} {agent['name']}")
        print(f"   Score:        {agent.get('score', 0):.4f}")
        print(f"   Confidence:   {agent.get('confidence', 0):.2%}")
        print(f"   Intent ID:    {result.get('intent_id')}")
        print(f"   Time:         {result.get('processing_time_ms')}ms")
        print(f"   Agents:       {len(result.get('proposals', []))}")
        if result.get("result"):
            print(f"\n--- Output (first 500 chars) ---")
            print(result["result"][:500])
    except SturnaError as e:
        print(f"Error: {e}")
        sys.exit(1)
