"""
billing.py — Stripe billing integration for llm-guard-kit SaaS.

Provides:
  - POST /billing/checkout    — Create Stripe Checkout session (subscription)
  - POST /billing/webhook     — Handle Stripe webhook events
  - GET  /billing/portal      — Customer billing portal redirect

Environment variables:
  STRIPE_SECRET_KEY       sk_live_... (or sk_test_... for testing)
  STRIPE_WEBHOOK_SECRET   whsec_...
  STRIPE_PRO_PRICE_ID     price_...
  FRONTEND_URL            https://your-app.vercel.app

Usage:
  from qppg_service.billing import make_billing_router
  app.include_router(make_billing_router(store, get_current_user), prefix="/billing", tags=["billing"])
"""

from __future__ import annotations

import logging
import os

from fastapi import APIRouter, Depends, HTTPException, Request

from qppg_service.store import ChainStore

logger = logging.getLogger(__name__)


def make_billing_router(store: ChainStore, get_current_user) -> APIRouter:
    """Build and return the billing APIRouter bound to the given ChainStore."""

    router = APIRouter()

    FRONTEND_URL = os.environ.get("FRONTEND_URL", "http://localhost:3000")

    def _stripe():
        try:
            import stripe as _stripe
        except ImportError:
            raise HTTPException(
                500,
                "stripe not installed — run: pip install 'llm-guard-kit[saas]'",
            )
        secret = os.environ.get("STRIPE_SECRET_KEY", "")
        if not secret:
            raise HTTPException(500, "STRIPE_SECRET_KEY not configured")
        _stripe.api_key = secret
        return _stripe

    # ── Checkout ──────────────────────────────────────────────────────────────

    @router.post("/checkout")
    async def create_checkout(user: dict = Depends(get_current_user)):
        """Create a Stripe Checkout session for the Pro subscription."""
        stripe = _stripe()
        price_id = os.environ.get("STRIPE_PRO_PRICE_ID", "")
        if not price_id:
            raise HTTPException(500, "STRIPE_PRO_PRICE_ID not configured")

        session = stripe.checkout.Session.create(
            customer_email=user["email"],
            client_reference_id=str(user["id"]),
            mode="subscription",
            line_items=[{"price": price_id, "quantity": 1}],
            success_url=f"{FRONTEND_URL}/app?upgraded=1",
            cancel_url=f"{FRONTEND_URL}/pricing",
        )
        return {"checkout_url": session.url}

    # ── Webhook ───────────────────────────────────────────────────────────────

    @router.post("/webhook")
    async def stripe_webhook(request: Request):
        """
        Handle Stripe webhook events.
        Must receive raw bytes — do NOT let FastAPI parse the body.
        """
        try:
            import stripe as _stripe_mod
        except ImportError:
            raise HTTPException(500, "stripe not installed")

        webhook_secret = os.environ.get("STRIPE_WEBHOOK_SECRET", "")
        if not webhook_secret:
            raise HTTPException(500, "STRIPE_WEBHOOK_SECRET not configured")

        secret_key = os.environ.get("STRIPE_SECRET_KEY", "")
        if not secret_key:
            raise HTTPException(500, "STRIPE_SECRET_KEY not configured")
        _stripe_mod.api_key = secret_key

        payload = await request.body()
        sig_header = request.headers.get("stripe-signature", "")

        try:
            event = _stripe_mod.Webhook.construct_event(payload, sig_header, webhook_secret)
        except _stripe_mod.error.SignatureVerificationError:
            raise HTTPException(400, "Invalid Stripe signature")
        except Exception as exc:
            raise HTTPException(400, f"Webhook error: {exc}")

        event_type = event["type"]
        data = event["data"]["object"]

        if event_type == "checkout.session.completed":
            user_id_str = data.get("client_reference_id")
            if user_id_str:
                try:
                    user_id = int(user_id_str)
                except ValueError:
                    logger.warning("checkout.session.completed: non-integer client_reference_id %s", user_id_str)
                    return {"ok": True}
                customer_id = data.get("customer", "")
                subscription_id = data.get("subscription", "")
                store.update_user_plan(user_id, "pro", customer_id, subscription_id)
                logger.info("User %d upgraded to Pro (sub=%s)", user_id, subscription_id)

        elif event_type == "customer.subscription.deleted":
            customer_id = data.get("customer", "")
            if customer_id:
                # Find user by stripe_customer_id
                with store._conn() as conn:
                    row = conn.execute(
                        "SELECT id FROM users WHERE stripe_customer_id=?",
                        (customer_id,),
                    ).fetchone()
                if row:
                    store.update_user_plan(row["id"], "free", customer_id, "")
                    logger.info("User %d downgraded to Free (sub cancelled)", row["id"])

        elif event_type == "invoice.payment_failed":
            # Grace period — log only, don't downgrade immediately
            customer_id = data.get("customer", "")
            logger.warning("Payment failed for Stripe customer %s", customer_id)

        else:
            logger.debug("Unhandled Stripe event: %s", event_type)

        return {"ok": True}

    # ── Customer portal ───────────────────────────────────────────────────────

    @router.get("/portal")
    async def billing_portal(user: dict = Depends(get_current_user)):
        """Return a Stripe Customer Portal URL for the current user."""
        stripe = _stripe()
        customer_id = user.get("stripe_customer_id", "")
        if not customer_id:
            raise HTTPException(400, "No Stripe customer on file — please subscribe first")

        session = stripe.billing_portal.Session.create(
            customer=customer_id,
            return_url=f"{FRONTEND_URL}/app",
        )
        return {"portal_url": session.url}

    return router
