import logging
from datetime import datetime, timedelta
from typing import List
from uuid import UUID

import stripe
from fastapi import APIRouter, Depends, HTTPException, Request, status
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import func, select

from .. import settings
from ..models import UsageEvent, UsageEventType
from ..main import get_current_account, get_session
from ..models import Account

log = logging.getLogger(__name__)
router = APIRouter(prefix="/api/billing", tags=["billing"])

# Configure Stripe API key from settings
if hasattr(settings, "STRIPE_SECRET_KEY") and settings.STRIPE_SECRET_KEY:
    stripe.api_key = settings.STRIPE_SECRET_KEY


class UsageSummary(BaseModel):
    """Response model for aggregated usage data."""

    event_type: UsageEventType
    total_quantity: int


@router.get("/usage", response_model=List[UsageSummary])
async def get_usage(
    account_id: UUID = Depends(get_current_account),
    db: AsyncSession = Depends(get_session),
):
    """
    Retrieves aggregated usage data for the current account for the
    current billing period (last 30 days).
    """
    # For simplicity, current billing period is the last 30 days
    billing_period_start = datetime.utcnow() - timedelta(days=30)

    stmt = (
        select(
            UsageEvent.event_type, func.sum(UsageEvent.quantity).label("total_quantity")
        )
        .where(UsageEvent.account_id == account_id)
        .where(UsageEvent.timestamp >= billing_period_start)
        .group_by(UsageEvent.event_type)
    )
    result = await db.execute(stmt)
    usage_data = result.all()

    return [
        UsageSummary(event_type=row.event_type, total_quantity=row.total_quantity)
        for row in usage_data
    ]


@router.post("/webhook/stripe")
async def stripe_webhook(request: Request, db: AsyncSession = Depends(get_session)):
    """
    Handles incoming webhooks from Stripe to manage subscription status.
    This endpoint should be protected and only accessible by Stripe.
    """
    payload = await request.body()
    sig_header = request.headers.get("stripe-signature")
    endpoint_secret = settings.STRIPE_WEBHOOK_SECRET

    if not endpoint_secret:
        log.error("STRIPE_WEBHOOK_SECRET is not configured.")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Webhook secret not configured.",
        )

    try:
        event = stripe.Webhook.construct_event(payload, sig_header, endpoint_secret)
    except ValueError as e:
        # Invalid payload
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    except stripe.error.SignatureVerificationError as e:
        # Invalid signature
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))

    # Handle the event
    event_data = event["data"]["object"]
    event_type = event["type"]

    log.info(f"Received Stripe webhook: {event_type}")

    if event_type.startswith("customer.subscription."):
        customer_id = event_data["customer"]
        # In a real application, you would add fields to the Account model
        # to store subscription_id, status, plan_id, etc.
        # For now, we just log the event.
        stmt = select(Account).where(Account.stripe_customer_id == customer_id)
        result = await db.execute(stmt)
        account = result.scalar_one_or_none()

        if account:
            log.info(
                f"Subscription event '{event_type}' for account {account.id} (Stripe Customer: {customer_id})"
            )
            # Example:
            # account.subscription_status = event_data['status']
            # db.add(account)
            # await db.commit()
        else:
            log.warning(f"Webhook for unknown Stripe customer: {customer_id}")

    elif event_type == "invoice.payment_succeeded":
        customer_id = event_data["customer"]
        log.info(f"Invoice payment succeeded for Stripe customer: {customer_id}")
        # Here you might reset usage counters for the account.

    else:
        log.info(f"Unhandled Stripe event type: {event_type}")

    return {"status": "success"}
