"""
Auth Client
Client for communicating with server API
"""

import json
import urllib.request
import urllib.error
import ssl
from typing import Optional, Dict, Any, Tuple
from decimal import Decimal

from promptbridge.auth.storage import AuthStorage

# SSL configuration
try:
    import certifi
    SSL_CONTEXT = ssl.create_default_context(cafile=certifi.where())
except ImportError:
    # Use system certificates if certifi is not available
    SSL_CONTEXT = ssl.create_default_context()


class AuthClient:
    """Authentication API Client"""

    def __init__(self, server_url: Optional[str] = None):
        self.storage = AuthStorage()
        self.server_url = server_url or self.storage.get_server_url()

    def _request(
        self,
        method: str,
        endpoint: str,
        data: Optional[Dict] = None,
        auth: bool = False,
    ) -> Tuple[bool, Dict[str, Any]]:
        """Perform HTTP request"""
        url = f"{self.server_url}/api{endpoint}"

        headers = {"Content-Type": "application/json"}

        if auth:
            token = self.storage.get_token()
            if not token:
                return False, {"error": "Login required."}
            headers["Authorization"] = f"Bearer {token}"

        try:
            req = urllib.request.Request(
                url,
                data=json.dumps(data).encode("utf-8") if data else None,
                headers=headers,
                method=method,
            )

            with urllib.request.urlopen(req, timeout=30, context=SSL_CONTEXT) as resp:
                body = resp.read().decode("utf-8")
                return True, json.loads(body) if body else {}

        except urllib.error.HTTPError as e:
            try:
                error_body = json.loads(e.read().decode("utf-8"))
                return False, {"error": error_body.get("detail", str(e))}
            except:
                return False, {"error": f"HTTP {e.code}: {e.reason}"}
        except Exception as e:
            return False, {"error": str(e)}

    def login(self, email: str, password: str) -> Tuple[bool, str]:
        """Login"""
        success, result = self._request("POST", "/auth/login", {
            "email": email,
            "password": password,
        })

        if not success:
            return False, result.get("error", "Login failed")

        # Save authentication info
        self.storage.save({
            "access_token": result["token"]["access_token"],
            "user": result["user"],
            "balance": str(result["balance"]),
            "server_url": self.server_url,
        })

        return True, f"Welcome, {result['user']['username']}!"

    def register(self, email: str, username: str, password: str) -> Tuple[bool, str]:
        """Register"""
        success, result = self._request("POST", "/auth/register", {
            "email": email,
            "username": username,
            "password": password,
        })

        if not success:
            return False, result.get("error", "Registration failed")

        # Save authentication info
        self.storage.save({
            "access_token": result["token"]["access_token"],
            "user": result["user"],
            "balance": str(result["balance"]),
            "server_url": self.server_url,
        })

        return True, f"Registration complete! Welcome, {result['user']['username']}!"

    def logout(self) -> Tuple[bool, str]:
        """Logout"""
        self.storage.clear()
        return True, "Logged out successfully."

    def get_status(self) -> Tuple[bool, Dict[str, Any]]:
        """Get current status (user info + balance)"""
        if not self.storage.is_logged_in():
            return False, {"error": "Login required."}

        # Check balance
        success, balance_result = self._request("GET", "/tokens/balance", auth=True)

        if not success:
            # Token expired etc
            self.storage.clear()
            return False, {"error": "Session expired. Please login again."}

        user = self.storage.get_user()

        return True, {
            "user": user,
            "balance": balance_result.get("balance", "0"),
            "min_balance": balance_result.get("min_balance_required", "0.01"),
        }

    def check_balance(self) -> Tuple[bool, str, Decimal]:
        """Check if service is available

        Returns:
            tuple: (can_use, message, balance)
        """
        if not self.storage.is_logged_in():
            return False, "Login required.", Decimal("0")

        success, result = self._request("GET", "/billing/check", auth=True)

        if not success:
            error = result.get("error", "Balance check failed")
            if "expired" in error.lower() or "401" in error:
                self.storage.clear()
            return False, error, Decimal("0")

        return True, "OK", Decimal(result.get("balance", "0"))

    def deduct_credits(
        self,
        input_tokens: int,
        cached_input_tokens: int,
        output_tokens: int,
        description: Optional[str] = None,
    ) -> Tuple[bool, str, Decimal, Dict[str, Any]]:
        """Deduct credits (new API)

        Args:
            input_tokens: Number of input tokens
            cached_input_tokens: Number of cached input tokens
            output_tokens: Number of output tokens
            description: Description (optional)

        Returns:
            tuple: (success, message, new_balance, details)
        """
        if not self.storage.is_logged_in():
            return False, "Login required.", Decimal("0"), {}

        data = {
            "input_tokens": input_tokens,
            "cached_input_tokens": cached_input_tokens,
            "output_tokens": output_tokens,
        }
        if description:
            data["description"] = description

        success, result = self._request("POST", "/billing/deduct", data, auth=True)

        if not success:
            return False, result.get("error", "Credit deduction failed"), Decimal("0"), {}

        return (
            True,
            result.get("message", "OK"),
            Decimal(result.get("new_balance", "0")),
            {
                "credits_deducted": Decimal(result.get("credits_deducted", "0")),
                "input_tokens": result.get("input_tokens", 0),
                "cached_input_tokens": result.get("cached_input_tokens", 0),
                "output_tokens": result.get("output_tokens", 0),
            },
        )

    def deduct_tokens(self, api_cost: Decimal) -> Tuple[bool, str, Decimal]:
        """Deduct tokens (deprecated - for backward compatibility)

        Returns:
            tuple: (success, message, new_balance)
        """
        # Convert api_cost to input_tokens (approximate)
        estimated_input = int(api_cost * Decimal("1000000") / Decimal("0.05"))
        success, message, balance, _ = self.deduct_credits(estimated_input, 0, 0)
        return success, message, balance

    def is_logged_in(self) -> bool:
        """Check login status"""
        return self.storage.is_logged_in()

    def optimize_prompt(self, prompt: str) -> Tuple[bool, Dict[str, Any]]:
        """Optimize prompt (server API call)

        Returns:
            tuple: (success, result)
            result contains: optimized_prompt, credits_deducted, new_balance, usage
        """
        if not self.storage.is_logged_in():
            return False, {"error": "Login required."}

        success, result = self._request("POST", "/optimize", {
            "prompt": prompt,
        }, auth=True)

        if not success:
            return False, result

        return True, result
