import requests
from typing import Optional, Dict, Any, Union
from .types import (
    AuthTestResponse,
    CreateOrderInput,
    Order,
    OrderStatus,
    WalletsResponse,
    CreateInvoiceInput,
    Invoice,
    InvoiceStatus,
)
from .errors import CPTError, CPTAuthError

DEFAULT_BASE_URL = "https://api.cptpayment.com"


class CPTPayment:
    """CPTPayment SDK client."""

    def __init__(self, api_key: str, base_url: Optional[str] = None):
        """
        Initialize CPTPayment client.

        Args:
            api_key: Your CPTPayment API key
            base_url: Optional custom base URL (default: https://api.cptpayment.com)
        """
        if not api_key:
            raise CPTAuthError("API key is required")

        self.api_key = api_key
        self.base_url = base_url or DEFAULT_BASE_URL

    def _request(
        self,
        method: str,
        endpoint: str,
        data: Optional[Dict[str, Any]] = None,
        params: Optional[Dict[str, str]] = None,
    ) -> Any:
        """Make an HTTP request to the CPT API."""
        url = f"{self.base_url}{endpoint}"

        headers = {
            "Content-Type": "application/json",
            "X-api-key": self.api_key,
        }

        # Filter out None values from params
        if params:
            params = {k: v for k, v in params.items() if v is not None}

        try:
            response = requests.request(
                method=method,
                url=url,
                headers=headers,
                json=data if method in ("POST", "PUT", "PATCH") else None,
                params=params,
            )

            try:
                response_data = response.json()
            except ValueError:
                response_data = {}

            if not response.ok:
                error_message = (
                    response_data.get("message")
                    or response_data.get("error")
                    or f"Request failed with status {response.status_code}"
                )
                raise CPTError(error_message, response.status_code, response_data)

            return response_data

        except requests.RequestException as e:
            raise CPTError(f"Request failed: {str(e)}")

    def auth_test(self) -> AuthTestResponse:
        """
        Test API connection and get store info.

        Returns:
            AuthTestResponse with status, store_id, mode, credits
        """
        return self._request("GET", "/plugins/v2/stores/auth_test/")

    def create_order(
        self,
        order_id: str,
        price_amount: Union[str, float, int],
        price_currency: str,
        success_url: str,
        cancel_url: str,
        purchaser_email: Optional[str] = None,
        description: Optional[str] = None,
        title: Optional[str] = None,
    ) -> Order:
        """
        Create an order on CPT.

        Args:
            order_id: Your internal order ID
            price_amount: Order amount
            price_currency: Currency code (e.g., 'USD')
            success_url: URL to redirect after successful payment
            cancel_url: URL to redirect after cancelled payment
            purchaser_email: Optional customer email
            description: Optional order description
            title: Optional order title

        Returns:
            Order with order_id, store_id, status, invoice, payment_url
        """
        data = {
            "order_id": order_id,
            "price_amount": str(price_amount),
            "price_currency": price_currency,
            "purchaser_email": purchaser_email or "customer@example.com",
            "description": description,
            "title": title,
            "success_url": success_url,
            "cancel_url": cancel_url,
        }
        return self._request("POST", "/plugins/v2/orders/", data=data)

    def get_order_status(self, order_id: str) -> OrderStatus:
        """
        Get order status.

        Args:
            order_id: The CPT order ID

        Returns:
            OrderStatus with order_id, status, invoice
        """
        response = self._request("GET", f"/plugins/v2/orders/{order_id}/")
        order_data = response.get("data", {})

        return {
            "order_id": order_data.get("order_id"),
            "status": order_data.get("status", "awaiting"),
            "invoice": order_data.get("invoice"),
        }

    def verify_webhook(self, payload: Dict[str, Any], signature: str) -> bool:
        """
        Verify webhook signature.

        Args:
            payload: The webhook payload
            signature: The signature from headers

        Returns:
            True if valid, False otherwise

        Note:
            TODO: Implement actual signature verification based on CPT's method
        """
        # TODO: Implement actual signature verification
        return bool(payload)

    # ============ Advanced Methods (Custom UI) ============

    def get_wallets(
        self,
        order_id: str,
        store_id: Union[str, int],
        reservation_id: Optional[str] = None,
    ) -> WalletsResponse:
        """
        Get available wallets for an order.

        Args:
            order_id: The CPT order ID
            store_id: The store ID
            reservation_id: Optional reservation ID for rate locking

        Returns:
            WalletsResponse with available wallets and blockchains
        """
        params = {
            "order_id": order_id,
            "store_id": str(store_id),
            "send_wallet": "true",
            "reservation_id": reservation_id,
        }
        return self._request("GET", "/plugins/v2/stores/details/", params=params)

    def create_invoice(
        self,
        amount_usd: float,
        wallet_cc: str,
        wallet_bc: str,
        order_id: str,
        store_id: Union[str, int],
        reservation_id: Optional[str] = None,
    ) -> Invoice:
        """
        Create an invoice after wallet selection.

        Args:
            amount_usd: Amount in USD
            wallet_cc: Cryptocurrency code (e.g., 'BTC')
            wallet_bc: Blockchain code (e.g., 'bitcoin')
            order_id: The CPT order ID
            store_id: The store ID
            reservation_id: Optional reservation ID

        Returns:
            Invoice with id, status, payment details
        """
        data = {
            "amount_usd": amount_usd,
            "for_duration": None,
            "wallet": None,
            "currency": wallet_cc,
            "blockchain": wallet_bc,
            "wallet_cc": wallet_cc,
            "wallet_bc": wallet_bc,
            "purpose": "custom_store",
            "content_data": {
                "order_id": order_id,
                "store_id": store_id,
            },
        }

        if reservation_id:
            data["reservation_id"] = reservation_id

        return self._request("POST", "/invoices/", data=data)

    def get_invoice_status(self, invoice_id: str) -> InvoiceStatus:
        """
        Get invoice status for polling.

        Args:
            invoice_id: The invoice ID

        Returns:
            InvoiceStatus with current payment status
        """
        return self._request("POST", f"/invoices/{invoice_id}/pay/")

    def get_checkout_url(self, order_id: str, store_id: Union[str, int]) -> str:
        """
        Generate checkout URL for redirect flow.

        Args:
            order_id: The CPT order ID
            store_id: The store ID

        Returns:
            Checkout URL for redirect
        """
        checkout_base = self.base_url.replace("api.", "")
        return f"{checkout_base}/checkout/?plugins=1&order_id={order_id}&store_id={store_id}"
