# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
"""
Stripe Checkout service for billing credit top-ups.
Creates Checkout Sessions for redirect-based payment flow.
"""

import logging
from typing import Optional
from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit

from modules.shared.configuration import APP_CONFIG

logger = logging.getLogger(__name__)

# Server-side allowed amounts in CHF - never trust client
ALLOWED_AMOUNTS_CHF = [10, 25, 50, 100, 250, 500]


def _normalizeReturnUrl(returnUrl: str) -> str:
    """
    Validate and normalize an absolute frontend return URL.

    Allowed examples:
      - https://nyla.poweron-center.net/billing/transactions
      - https://nyla-int.poweron-center.net/billing/transactions?tab=overview
    """
    if not returnUrl:
        raise ValueError("returnUrl is required")

    parsed = urlsplit(returnUrl.strip())

    if parsed.scheme not in ("http", "https"):
        raise ValueError("returnUrl must use http or https")

    if not parsed.netloc:
        raise ValueError("returnUrl must contain a host")

    if parsed.username or parsed.password:
        raise ValueError("returnUrl must not contain credentials")

    query_items = [
        (key, value)
        for key, value in parse_qsl(parsed.query, keep_blank_values=True)
        if key not in {"success", "canceled", "session_id"}
    ]
    normalized_query = urlencode(query_items, doseq=True)
    normalized_path = parsed.path or "/"

    # Keep scheme + host + path + query, strip fragment for deterministic redirects.
    return urlunsplit((parsed.scheme, parsed.netloc, normalized_path, normalized_query, ""))


def create_checkout_session(
    mandate_id: str,
    user_id: Optional[str],
    amount_chf: float,
    return_url: str
) -> str:
    """
    Create a Stripe Checkout Session for credit top-up.
    
    Amount and currency are validated server-side. The client-provided amount
    must match an allowed preset.
    
    Args:
        mandate_id: Target mandate ID
        user_id: Target user ID (for PREPAY_USER) or None (for mandate pool)
        amount_chf: Amount in CHF (must be in ALLOWED_AMOUNTS_CHF)
        
    Returns:
        Stripe Checkout Session URL for redirect
        
    Raises:
        ValueError: If amount is invalid
    """
    import stripe
    
    # Validate amount server-side
    if amount_chf not in ALLOWED_AMOUNTS_CHF:
        raise ValueError(
            f"Invalid amount {amount_chf} CHF. Allowed: {ALLOWED_AMOUNTS_CHF}"
        )
    
    from modules.shared.stripeClient import getStripeClient
    stripe = getStripeClient()
    
    base_return_url = _normalizeReturnUrl(return_url)
    query_separator = "&" if "?" in base_return_url else "?"
    success_url = f"{base_return_url}{query_separator}success=true&session_id={{CHECKOUT_SESSION_ID}}"
    cancel_url = f"{base_return_url}{query_separator}canceled=true"
    
    # Amount in cents for Stripe (CHF uses 2 decimal places)
    amount_cents = int(round(amount_chf * 100))
    
    metadata = {
        "mandateId": mandate_id,
        "amountChf": str(amount_chf),
    }
    if user_id:
        metadata["userId"] = user_id
    
    session = stripe.checkout.Session.create(
        mode="payment",
        line_items=[
            {
                "price_data": {
                    "currency": "chf",
                    "unit_amount": amount_cents,
                    "product_data": {
                        "name": "Guthaben aufladen",
                        "description": "AI Service Guthaben (CHF)",
                    },
                },
                "quantity": 1,
            }
        ],
        success_url=success_url,
        cancel_url=cancel_url,
        metadata=metadata,
    )
    
    if not session or not session.url:
        raise ValueError("Stripe Checkout Session creation failed")
    
    logger.info(
        f"Created Stripe Checkout Session {session.id} for mandate {mandate_id}, "
        f"amount {amount_chf} CHF"
    )
    
    return session.url
