import json
from typing import Dict, Any, List, Optional

from t402.types import PaymentRequirements, PaywallConfig
from t402.common import t402_VERSION
from t402.evm_paywall_template import EVM_PAYWALL_TEMPLATE
from t402.svm_paywall_template import SVM_PAYWALL_TEMPLATE
from t402.ton_paywall_template import TON_PAYWALL_TEMPLATE
from t402.tron_paywall_template import TRON_PAYWALL_TEMPLATE
from t402.stacks_paywall_template import STACKS_PAYWALL_TEMPLATE
from t402.cosmos_paywall_template import COSMOS_PAYWALL_TEMPLATE
from t402.near_paywall_template import NEAR_PAYWALL_TEMPLATE


def _get_inline_template(network: str) -> str:
    """Get the inline (full embedded) template for the given network."""
    if network.startswith("solana:"):
        from t402.svm_paywall_template_inline import SVM_PAYWALL_TEMPLATE_INLINE
        return SVM_PAYWALL_TEMPLATE_INLINE
    if network.startswith("ton:"):
        from t402.ton_paywall_template_inline import TON_PAYWALL_TEMPLATE_INLINE
        return TON_PAYWALL_TEMPLATE_INLINE
    if network.startswith("tron:"):
        from t402.tron_paywall_template_inline import TRON_PAYWALL_TEMPLATE_INLINE
        return TRON_PAYWALL_TEMPLATE_INLINE
    if network.startswith("stacks:"):
        from t402.stacks_paywall_template_inline import STACKS_PAYWALL_TEMPLATE_INLINE
        return STACKS_PAYWALL_TEMPLATE_INLINE
    if network.startswith("cosmos:"):
        from t402.cosmos_paywall_template_inline import COSMOS_PAYWALL_TEMPLATE_INLINE
        return COSMOS_PAYWALL_TEMPLATE_INLINE
    if network.startswith("near:"):
        from t402.near_paywall_template_inline import NEAR_PAYWALL_TEMPLATE_INLINE
        return NEAR_PAYWALL_TEMPLATE_INLINE
    from t402.evm_paywall_template_inline import EVM_PAYWALL_TEMPLATE_INLINE
    return EVM_PAYWALL_TEMPLATE_INLINE


def get_paywall_template(network: str, delivery_mode: str = "cdn") -> str:
    """Get the appropriate paywall template for the given network.

    Args:
        network: CAIP-2 network identifier (e.g. "eip155:1")
        delivery_mode: "cdn" (default) for lightweight CDN shell,
                       "inline" for full embedded HTML
    """
    if delivery_mode == "inline":
        return _get_inline_template(network)

    if network.startswith("solana:"):
        return SVM_PAYWALL_TEMPLATE
    if network.startswith("ton:"):
        return TON_PAYWALL_TEMPLATE
    if network.startswith("tron:"):
        return TRON_PAYWALL_TEMPLATE
    if network.startswith("stacks:"):
        return STACKS_PAYWALL_TEMPLATE
    if network.startswith("cosmos:"):
        return COSMOS_PAYWALL_TEMPLATE
    if network.startswith("near:"):
        return NEAR_PAYWALL_TEMPLATE
    return EVM_PAYWALL_TEMPLATE


def is_browser_request(headers: Dict[str, Any]) -> bool:
    """
    Determine if request is from a browser vs API client.

    Args:
        headers: Dictionary of request headers (case-insensitive keys)

    Returns:
        True if request appears to be from a browser, False otherwise
    """
    headers_lower = {k.lower(): v for k, v in headers.items()}
    accept_header = headers_lower.get("accept", "")
    user_agent = headers_lower.get("user-agent", "")

    if "text/html" in accept_header and "Mozilla" in user_agent:
        return True

    return False


def create_t402_config(
    error: str,
    payment_requirements: List[PaymentRequirements],
    paywall_config: Optional[PaywallConfig] = None,
) -> Dict[str, Any]:
    """Create t402 configuration object from payment requirements."""

    requirements = payment_requirements[0] if payment_requirements else None
    display_amount = 0
    current_url = ""
    testnet = True

    if requirements:
        # Convert atomic amount back to USD (assuming USDC with 6 decimals)
        try:
            display_amount = (
                float(requirements.max_amount_required) / 1000000
            )  # USDC has 6 decimals
        except (ValueError, TypeError):
            display_amount = 0

        current_url = requirements.resource or ""
        testnet = requirements.network == "base-sepolia"

    # Get paywall config values or defaults
    config = paywall_config or {}

    # Create the window.t402 configuration object
    return {
        "amount": display_amount,
        "paymentRequirements": [
            req.model_dump(by_alias=True) for req in payment_requirements
        ],
        "testnet": testnet,
        "currentUrl": current_url,
        "error": error,
        "t402_version": t402_VERSION,
        "appName": config.get("app_name", ""),
        "appLogo": config.get("app_logo", ""),
    }


def inject_payment_data(
    html_content: str,
    error: str,
    payment_requirements: List[PaymentRequirements],
    paywall_config: Optional[PaywallConfig] = None,
) -> str:
    """Inject payment requirements into HTML as JavaScript variables."""

    # Create t402 configuration object
    t402_config = create_t402_config(error, payment_requirements, paywall_config)

    # Create the configuration script (matching TypeScript pattern)
    log_on_testnet = (
        "console.log('Payment requirements initialized:', window.t402);"
        if t402_config["testnet"]
        else ""
    )

    config_script = f"""
  <script>
    window.t402 = {json.dumps(t402_config)};
    {log_on_testnet}
  </script>"""

    # Inject the configuration script into the head (same as TypeScript)
    return html_content.replace("</head>", f"{config_script}\n</head>")


def get_paywall_html(
    error: str,
    payment_requirements: List[PaymentRequirements],
    paywall_config: Optional[PaywallConfig] = None,
) -> str:
    """
    Load paywall HTML and inject payment data.

    Args:
        error: Error message to display
        payment_requirements: List of payment requirements
        paywall_config: Optional paywall UI configuration

    Returns:
        Complete HTML with injected payment data
    """
    if not payment_requirements:
        raise ValueError("payment_requirements cannot be empty")
    network = payment_requirements[0].network
    delivery_mode = (paywall_config or {}).get("delivery_mode", "cdn")
    template = get_paywall_template(network, delivery_mode)
    return inject_payment_data(template, error, payment_requirements, paywall_config)
