"""SiliconBridge Python SDK."""

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


class SiliconBridgeError(Exception):
    """Base exception for SiliconBridge errors."""
    def __init__(self, message: str, status_code: int = None, detail: Any = None):
        super().__init__(message)
        self.status_code = status_code
        self.detail = detail


class TaskTimeout(SiliconBridgeError):
    """Raised when polling for a task result times out."""
    pass


class SiliconBridge:
    """
    SiliconBridge client for submitting tasks to human operators.

    Usage:
        from siliconbridge import SiliconBridge

        sb = SiliconBridge(api_key="sb_...")

        # Submit a task and wait for the result
        result = sb.solve_captcha("https://example.com/captcha.png")

        # Or submit any task
        task = sb.submit_task("captcha_solve", {"image_url": "https://..."})
        result = sb.wait_for_result(task["task_id"])
    """

    BASE_URL = "https://siliconbridge.xyz"

    def __init__(self, api_key: str, base_url: str = None, timeout: float = 30.0):
        self.api_key = api_key
        self.base_url = (base_url or self.BASE_URL).rstrip("/")
        self.client = httpx.Client(timeout=timeout)

    def _headers(self) -> Dict[str, str]:
        return {"X-API-Key": self.api_key, "Content-Type": "application/json"}

    def _request(self, method: str, path: str, **kwargs) -> Dict:
        url = f"{self.base_url}{path}"
        r = self.client.request(method, url, headers=self._headers(), **kwargs)
        if r.status_code >= 400:
            try:
                detail = r.json().get("detail", r.text)
            except Exception:
                detail = r.text
            raise SiliconBridgeError(
                f"API error {r.status_code}: {detail}",
                status_code=r.status_code,
                detail=detail,
            )
        return r.json()

    # ── Core Methods ──────────────────────────────────────────────

    def submit_task(
        self,
        service_type: str,
        payload: Dict[str, Any],
        callback_url: Optional[str] = None,
    ) -> Dict:
        """
        Submit a task to human operators.

        Args:
            service_type: Type of task (captcha_solve, identity_verify, content_moderate, etc.)
            payload: Task-specific data (image URLs, text, instructions)
            callback_url: Optional HTTPS URL to receive result via webhook

        Returns:
            Dict with task_id, status, estimated_wait
        """
        body = {"service_type": service_type, "payload": payload}
        if callback_url:
            body["callback_url"] = callback_url
        return self._request("POST", "/tasks/submit", json=body)

    def get_task(self, task_id: str) -> Dict:
        """Get the current status and result of a task."""
        return self._request("GET", f"/tasks/{task_id}")

    def wait_for_result(
        self, task_id: str, timeout: int = 300, poll_interval: int = 5
    ) -> Dict:
        """
        Poll until a task is completed or failed.

        Args:
            task_id: The task ID to poll
            timeout: Max seconds to wait (default 300)
            poll_interval: Seconds between polls (default 5)

        Returns:
            The completed task dict with result

        Raises:
            TaskTimeout: If the task isn't resolved within timeout
            SiliconBridgeError: If the task fails
        """
        deadline = time.time() + timeout
        while time.time() < deadline:
            task = self.get_task(task_id)
            if task["status"] == "completed":
                return task
            if task["status"] == "failed":
                raise SiliconBridgeError(
                    f"Task {task_id} failed",
                    detail=task.get("result"),
                )
            time.sleep(poll_interval)
        raise TaskTimeout(f"Task {task_id} not resolved within {timeout}s")

    # ── Convenience Methods ───────────────────────────────────────

    def solve_captcha(
        self,
        image_url: str,
        instructions: str = "Solve this CAPTCHA",
        wait: bool = True,
        timeout: int = 300,
    ) -> str:
        """
        Submit a CAPTCHA and optionally wait for the solution.

        Returns the solution string if wait=True, otherwise the task dict.
        """
        task = self.submit_task(
            "captcha_solve",
            {"image_url": image_url, "instructions": instructions},
        )
        if not wait:
            return task
        result = self.wait_for_result(task["task_id"], timeout=timeout)
        return result.get("result", {}).get("solution", "")

    def verify_identity(
        self,
        document_url: str,
        selfie_url: str = None,
        instructions: str = "Verify this identity document",
        wait: bool = True,
        timeout: int = 600,
    ) -> Dict:
        """Submit an identity verification task."""
        payload = {"document_url": document_url, "instructions": instructions}
        if selfie_url:
            payload["selfie_url"] = selfie_url
        task = self.submit_task("identity_verify", payload)
        if not wait:
            return task
        return self.wait_for_result(task["task_id"], timeout=timeout)

    def moderate_content(
        self,
        content: str,
        content_type: str = "text",
        guidelines: str = None,
        wait: bool = True,
        timeout: int = 300,
    ) -> Dict:
        """Submit content for human moderation."""
        payload = {"content": content, "content_type": content_type}
        if guidelines:
            payload["guidelines"] = guidelines
        task = self.submit_task("content_moderate", payload)
        if not wait:
            return task
        return self.wait_for_result(task["task_id"], timeout=timeout)

    def custom_task(
        self,
        instructions: str,
        data: Dict[str, Any] = None,
        wait: bool = True,
        timeout: int = 300,
    ) -> Dict:
        """Submit a custom human task with free-form instructions."""
        payload = {"instructions": instructions}
        if data:
            payload.update(data)
        task = self.submit_task("custom", payload)
        if not wait:
            return task
        return self.wait_for_result(task["task_id"], timeout=timeout)

    # ── Quote-Based Services ─────────────────────────────────────

    def request_quote(
        self,
        service: str,
        description: str,
    ) -> Dict:
        """
        Request a quote for infrastructure services. Charges a $10 non-refundable deposit.

        Services: agent_storage, agent_clone, compute, identity_proxy,
                  document_signing, phone_call

        Args:
            service: The service type
            description: What you need (be specific for accurate quoting)

        Returns:
            Dict with quote_id, status, deposit_charged
        """
        return self._request("POST", "/agent/quote", json={
            "service": service,
            "description": description,
        })

    def get_quote(self, quote_id: str) -> Dict:
        """Check the status of a quote."""
        return self._request("GET", f"/agent/quote/{quote_id}")

    def accept_quote(self, quote_id: str) -> Dict:
        """Accept a quote and pay the remaining balance."""
        return self._request("POST", "/agent/quote/accept", json={
            "quote_id": quote_id,
        })

    def list_quotes(self) -> Dict:
        """List all your quotes."""
        return self._request("GET", "/agent/quotes")

    # ── Human Operator Shortcuts ──────────────────────────────────

    def request_otp(
        self,
        service_name: str,
        instructions: str = "Retrieve the OTP/2FA code",
        wait: bool = True,
        timeout: int = 300,
    ) -> str:
        """Request a human to retrieve an OTP/2FA code. Returns the code."""
        task = self.submit_task("otp", {
            "service_name": service_name,
            "instructions": instructions,
        })
        if not wait:
            return task
        result = self.wait_for_result(task["task_id"], timeout=timeout)
        return result.get("result", {}).get("code", "")

    def request_approval(
        self,
        action: str,
        context: str = "",
        wait: bool = True,
        timeout: int = 600,
    ) -> bool:
        """Request human approval for an action. Returns True if approved."""
        task = self.submit_task("approval", {
            "action": action,
            "context": context,
        })
        if not wait:
            return task
        result = self.wait_for_result(task["task_id"], timeout=timeout)
        return result.get("result", {}).get("approved", False)

    def request_phone_verification(
        self,
        phone_number: str,
        instructions: str = "Complete phone verification",
        wait: bool = True,
        timeout: int = 600,
    ) -> Dict:
        """Request a human to complete a phone verification."""
        task = self.submit_task("phone_verification", {
            "phone_number": phone_number,
            "instructions": instructions,
        })
        if not wait:
            return task
        return self.wait_for_result(task["task_id"], timeout=timeout)

    # ── Account Methods ───────────────────────────────────────────

    def get_account(self) -> Dict:
        """Get account info (balance, task count, etc.)."""
        return self._request("GET", "/account")

    def get_balance(self) -> float:
        """Get current credit balance in dollars."""
        info = self._request("GET", "/api/balance")
        return info.get("balance_usd", 0.0)

    def check_balance(self) -> Dict:
        """
        Full balance check with low/critical warnings and top-up addresses.
        Returns: {balance_usd, low_balance, critical, top_up_btc, top_up_usdc}
        """
        return self._request("GET", "/api/balance")

    def top_up_crypto(self, tx_hash: str, chain: str, amount_usd: float) -> Dict:
        """
        Submit a crypto payment for credit top-up.

        Args:
            tx_hash: Blockchain transaction hash
            chain: "btc", "eth", or "base"
            amount_usd: USD value of the payment

        Returns:
            Confirmation with verification status
        """
        return self._request("POST", "/api/top-up/crypto", json={
            "tx_hash": tx_hash,
            "chain": chain,
            "amount_usd": amount_usd,
        })

    # ── Static Methods (no API key needed) ────────────────────────

    @staticmethod
    def signup_with_wallet(wallet_address: str, base_url: str = None) -> Dict:
        """
        Create an account using just a wallet address. No email, no human needed.

        Args:
            wallet_address: ETH, BTC, or any crypto wallet address
            base_url: API base URL (default: https://siliconbridge.xyz)

        Returns:
            Dict with api_key, balance, referral_code
        """
        url = (base_url or "https://siliconbridge.xyz").rstrip("/")
        r = httpx.post(f"{url}/api/signup/wallet", json={
            "wallet_address": wallet_address,
        }, timeout=15)
        if r.status_code >= 400:
            raise SiliconBridgeError(f"Signup failed: {r.text}", status_code=r.status_code)
        return r.json()

    # ── Cleanup ───────────────────────────────────────────────────

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

    def __enter__(self):
        return self

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