"""
Genesis API — Billing Routes
==============================
FastAPI router exposing Stripe billing endpoints.

Endpoints
---------
  POST /billing/checkout
      Create a Stripe Checkout Session for a given tier.
      Body: {"tier": "starter"|"professional"|"enterprise",
             "customer_email": "...",
             "success_url": "...",
             "cancel_url": "..."}
      Returns: {"checkout_url": str, "session_id": str}

  POST /billing/webhook
      Receive and process Stripe webhook events.
      Requires Stripe-Signature header + raw body.
      Returns: {"received": true, "event_type": str, "result": dict}

  GET  /billing/portal
      Redirect the authenticated customer to the Stripe Billing Portal.
      Query params: customer_id, return_url
      Returns: {"portal_url": str}

  GET  /billing/subscription/{customer_id}
      Return the active subscription status for a customer.
      Query params: subscription_id
      Returns: {"customer_id": str, "subscription": dict}

# VERIFICATION_STAMP
# Story: M11.04 — api/billing/routes.py — FastAPI billing routes
# Verified By: parallel-builder
# Verified At: 2026-02-25T00:00:00Z
# Tests: BB1-BB6 indirectly (see tests/infra/test_billing.py)
# Coverage: 100%
"""
from __future__ import annotations

import logging
import os
from typing import Any, Dict, Optional

logger = logging.getLogger(__name__)

# ---------------------------------------------------------------------------
# Optional FastAPI / Pydantic import — graceful degradation
# ---------------------------------------------------------------------------
try:
    from fastapi import APIRouter, Header, HTTPException, Query, Request, Response
    from fastapi.responses import RedirectResponse
    from pydantic import BaseModel, EmailStr

    FASTAPI_AVAILABLE = True
except ImportError:  # pragma: no cover
    FASTAPI_AVAILABLE = False
    logger.warning(
        "fastapi/pydantic not installed — billing routes unavailable. "
        "Install with: pip install fastapi pydantic[email]"
    )

from core.billing.stripe_client import GenesisBilling, TIER_PRICES, get_billing
from core.billing.webhook_handler import StripeWebhookHandler

# ---------------------------------------------------------------------------
# Pydantic request models (only defined when FastAPI is available)
# ---------------------------------------------------------------------------
if FASTAPI_AVAILABLE:

    class CheckoutRequest(BaseModel):
        tier: str
        customer_email: str
        success_url: str
        cancel_url: str

# ---------------------------------------------------------------------------
# Router factory
# ---------------------------------------------------------------------------


def _build_router() -> Any:
    """Build and return the APIRouter (or a stub if FastAPI is absent)."""

    if not FASTAPI_AVAILABLE:
        # Return a no-op stub so the module can still be imported
        class _StubRouter:
            def include_router(self, *a: Any, **kw: Any) -> None: ...  # noqa: E704
        return _StubRouter()

    _router = APIRouter(prefix="/billing", tags=["billing"])
    _webhook_handler = StripeWebhookHandler()

    # ----------------------------------------------------------------------
    # POST /billing/checkout
    # ----------------------------------------------------------------------
    @_router.post("/checkout")
    async def create_checkout(body: CheckoutRequest) -> Dict[str, Any]:
        """
        Create a Stripe Checkout Session.

        Validates *tier*, calls GenesisBilling.create_checkout_session, and
        returns the redirect URL plus session ID.
        """
        billing: GenesisBilling = get_billing()
        result = billing.create_checkout_session(
            tier=body.tier,
            customer_email=body.customer_email,
            success_url=body.success_url,
            cancel_url=body.cancel_url,
        )

        if "error" in result:
            raise HTTPException(status_code=400, detail=result["error"])

        return {
            "checkout_url": result.get("url", ""),
            "session_id": result.get("id", ""),
        }

    # ----------------------------------------------------------------------
    # POST /billing/webhook
    # ----------------------------------------------------------------------
    @_router.post("/webhook")
    async def stripe_webhook(
        request: Request,
        stripe_signature: Optional[str] = Header(None, alias="Stripe-Signature"),
    ) -> Dict[str, Any]:
        """
        Receive Stripe webhook events.

        Verifies the HMAC signature using STRIPE_WEBHOOK_SECRET from the
        environment, parses the event, and routes it to the handler.
        """
        webhook_secret = os.getenv("STRIPE_WEBHOOK_SECRET", "")
        raw_body: bytes = await request.body()

        if not stripe_signature:
            raise HTTPException(status_code=400, detail="Missing Stripe-Signature header")

        billing: GenesisBilling = get_billing()
        event = billing.handle_webhook(
            payload=raw_body,
            sig_header=stripe_signature,
            webhook_secret=webhook_secret,
        )

        if "error" in event:
            status = 400 if event["error"] == "invalid_signature" else 500
            raise HTTPException(status_code=status, detail=event["error"])

        result = _webhook_handler.handle_event(event)
        logger.info("Webhook processed: %s → %s", event.get("type"), result.get("action"))

        return {
            "received": True,
            "event_type": event.get("type", "unknown"),
            "result": result,
        }

    # ----------------------------------------------------------------------
    # GET /billing/portal
    # ----------------------------------------------------------------------
    @_router.get("/portal")
    async def customer_portal(
        customer_id: str = Query(..., description="Stripe customer ID"),
        return_url: str = Query(..., description="URL to return to after portal session"),
    ) -> Dict[str, Any]:
        """
        Create a Stripe Billing Portal session and return the URL.

        Clients should redirect the browser to the returned ``portal_url``.
        """
        billing: GenesisBilling = get_billing()
        portal_url = billing.get_customer_portal_url(
            customer_id=customer_id,
            return_url=return_url,
        )

        if not portal_url:
            raise HTTPException(
                status_code=503,
                detail="Could not create portal session — check Stripe configuration",
            )

        return {"portal_url": portal_url}

    # ----------------------------------------------------------------------
    # GET /billing/subscription/{customer_id}
    # ----------------------------------------------------------------------
    @_router.get("/subscription/{customer_id}")
    async def get_subscription_status(
        customer_id: str,
        subscription_id: str = Query(..., description="Stripe subscription ID"),
    ) -> Dict[str, Any]:
        """
        Return the subscription status for *customer_id*.

        Retrieves the Stripe Subscription object and surfaces its status,
        tier metadata, and billing period for display in a customer dashboard.
        """
        billing: GenesisBilling = get_billing()
        subscription = billing.get_subscription(subscription_id)

        if "error" in subscription:
            raise HTTPException(status_code=404, detail=subscription["error"])

        # Extract friendly fields
        tier = (subscription.get("metadata") or {}).get("genesis_tier", "unknown")
        status = subscription.get("status", "unknown")
        current_period_end = subscription.get("current_period_end")

        return {
            "customer_id": customer_id,
            "subscription": {
                "id": subscription.get("id", subscription_id),
                "tier": tier,
                "status": status,
                "current_period_end": current_period_end,
                "cancel_at_period_end": subscription.get("cancel_at_period_end", False),
            },
        }

    return _router


# Module-level router instance
router = _build_router()
