"""Billing router: plan, usage, checkout, and the Stripe webhook."""

from __future__ import annotations

import uuid

from fastapi import APIRouter, Depends, HTTPException, Request, status
from pydantic import BaseModel
from sqlalchemy.orm import Session

from legate.api.deps import Principal, require
from legate.audit.service import record as audit_record
from legate.billing import PLANS
from legate.billing.service import usage_summary
from legate.billing.stripe_client import StripeError, create_checkout_session, parse_event
from legate.config import get_settings
from legate.db.models.workspace import Workspace
from legate.db.session import get_db
from legate.observability.logging import get_logger
from legate.policy.rbac import Permission

logger = get_logger(__name__)
router = APIRouter(tags=["billing"])


def _workspace(db: Session, workspace_id: uuid.UUID) -> Workspace:
    ws = db.get(Workspace, workspace_id)
    if ws is None:
        raise HTTPException(status.HTTP_404_NOT_FOUND, detail="workspace not found")
    return ws


@router.get("/billing")
def get_billing(
    principal: Principal = Depends(require(Permission.VIEW)),
    db: Session = Depends(get_db),
) -> dict:
    ws = _workspace(db, principal.workspace_id)
    return {
        **usage_summary(db, ws),
        "available_plans": [p.as_dict() for p in PLANS.values()],
    }


@router.get("/usage")
def get_usage(
    principal: Principal = Depends(require(Permission.VIEW)),
    db: Session = Depends(get_db),
) -> dict:
    return usage_summary(db, _workspace(db, principal.workspace_id))


class CheckoutRequest(BaseModel):
    plan: str
    success_url: str = "http://localhost:3000/admin?billing=success"
    cancel_url: str = "http://localhost:3000/admin?billing=cancel"


@router.post("/billing/checkout")
def checkout(
    body: CheckoutRequest,
    principal: Principal = Depends(require(Permission.MANAGE_WORKSPACE)),
) -> dict:
    if body.plan not in PLANS:
        raise HTTPException(422, detail=f"unknown plan: {body.plan}")
    try:
        url = create_checkout_session(
            workspace_id=str(principal.workspace_id),
            plan=body.plan,
            success_url=body.success_url,
            cancel_url=body.cancel_url,
        )
    except StripeError as exc:
        raise HTTPException(status.HTTP_503_SERVICE_UNAVAILABLE, detail=str(exc)) from exc
    return {"checkout_url": url}


@router.post("/billing/webhook")
async def stripe_webhook(request: Request, db: Session = Depends(get_db)) -> dict:
    payload = await request.body()
    signature = request.headers.get("stripe-signature")
    try:
        event = parse_event(payload, signature)
    except StripeError as exc:
        raise HTTPException(status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc

    event_type = event.get("type", "")
    obj = (event.get("data") or {}).get("object") or {}
    metadata = obj.get("metadata") or {}
    ws_id = metadata.get("workspace_id")
    if not ws_id:
        return {"ignored": True}

    ws = db.get(Workspace, uuid.UUID(ws_id))
    if ws is None:
        return {"ignored": True}

    if event_type == "customer.subscription.deleted":
        ws.plan = get_settings().default_plan
    else:
        plan = metadata.get("plan")
        if plan in PLANS:
            ws.plan = plan
    audit_record(
        db,
        workspace_id=ws.id,
        actor="stripe",
        action="billing.plan_changed",
        target=ws.plan,
        metadata={"event": event_type},
    )
    db.commit()
    return {"ok": True, "plan": ws.plan}
