"""Stripe billing routes (paid tier)."""

import logging

from fastapi import APIRouter, Depends, HTTPException, Request, status

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from mixlift.billing.service import update_user_tier
from mixlift.config import settings
from mixlift.deps import get_current_user, get_db
from mixlift.projects.models import User

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/billing", tags=["billing"])


@router.post("/create-checkout-session")
async def create_checkout_session(
    plan: str,
    user: User = Depends(get_current_user),
):
    if not settings.stripe_secret_key:
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail="Billing not configured",
        )

    if plan != "pro":
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid plan"
        )

    import stripe

    stripe.api_key = settings.stripe_secret_key

    price_id = settings.stripe_pro_price_id
    if not price_id:
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail="Stripe price not configured",
        )

    session = stripe.checkout.Session.create(
        customer_email=user.email,
        payment_method_types=["card"],
        line_items=[{"price": price_id, "quantity": 1}],
        mode="subscription",
        metadata={"user_id": str(user.id), "plan": "pro"},
        success_url=f"{settings.frontend_url}/?billing=success",
        cancel_url=f"{settings.frontend_url}/?billing=cancel",
    )

    logger.info("Created checkout session for user=%s plan=pro", user.id)
    return {"checkout_url": session.url}


@router.post("/webhook")
async def stripe_webhook(request: Request):
    """Handle Stripe webhook events."""
    if not settings.stripe_secret_key:
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail="Billing not configured",
        )

    import stripe

    stripe.api_key = settings.stripe_secret_key

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

    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, settings.stripe_webhook_secret
        )
    except (ValueError, stripe.error.SignatureVerificationError):
        logger.warning("Invalid webhook signature")
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid webhook")

    data_obj = event["data"]["object"]
    event_type = event["type"]
    logger.info("Stripe webhook received: %s", event_type)

    if event_type == "checkout.session.completed":
        user_id = data_obj.get("metadata", {}).get("user_id")
        plan = data_obj.get("metadata", {}).get("plan")
        if user_id and plan:
            customer_id = data_obj.get("customer")
            if customer_id:
                await _save_stripe_customer_id(user_id, customer_id)
            await update_user_tier(user_id=user_id, plan=plan, status="active")
            logger.info("Checkout completed: user=%s plan=%s", user_id, plan)
        else:
            logger.warning("checkout.session.completed missing metadata: user_id=%s plan=%s", user_id, plan)

    elif event_type in (
        "customer.subscription.updated",
        "customer.subscription.deleted",
    ):
        customer_id = data_obj.get("customer")
        sub_status = data_obj.get("status", "canceled")
        plan = _resolve_plan_from_subscription(data_obj)
        if customer_id:
            user_id = await _get_user_id_by_stripe_customer(customer_id)
            if user_id:
                await update_user_tier(
                    user_id=user_id, plan=plan, status=sub_status
                )
                logger.info("Subscription %s: user=%s plan=%s status=%s", event_type, user_id, plan, sub_status)
            else:
                logger.warning("No user found for stripe_customer_id=%s", customer_id)
        else:
            logger.warning("Subscription event missing customer_id")

    elif event_type == "invoice.payment_failed":
        customer_id = data_obj.get("customer")
        if customer_id:
            user_id = await _get_user_id_by_stripe_customer(customer_id)
            if user_id:
                logger.warning("Payment failed: user=%s customer=%s", user_id, customer_id)

    return {"status": "ok"}


def _resolve_plan_from_subscription(subscription_obj: dict) -> str:
    """Map a Stripe subscription's price ID back to a plan name."""
    price_to_plan = {}
    if settings.stripe_pro_price_id:
        price_to_plan[settings.stripe_pro_price_id] = "pro"

    items = subscription_obj.get("items", {}).get("data", [])
    for item in items:
        price_id = item.get("price", {}).get("id")
        if price_id in price_to_plan:
            return price_to_plan[price_id]
    return "pro"


async def _get_user_id_by_stripe_customer(customer_id: str) -> str | None:
    """Look up user ID from their Stripe customer ID."""
    from mixlift.db import async_session

    async with async_session() as session:
        result = await session.execute(
            select(User).where(User.stripe_customer_id == customer_id)
        )
        user = result.scalar_one_or_none()
        return str(user.id) if user else None


async def _save_stripe_customer_id(user_id: str, customer_id: str) -> None:
    """Persist the Stripe customer ID on the user record."""
    from mixlift.db import async_session

    async with async_session() as session:
        result = await session.execute(
            select(User).where(User.id == user_id)
        )
        user = result.scalar_one_or_none()
        if user and not user.stripe_customer_id:
            user.stripe_customer_id = customer_id
            await session.commit()
