"""Billing invoices endpoints for payment history."""

from datetime import datetime

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session

from ...database import get_db_session
from ...logger import get_logger
from ...middleware.auth.dependencies import get_current_user
from ...middleware.rate_limits import billing_rate_limit_dependency
from ...models.api.billing.invoice import (
  Invoice,
  InvoiceLineItem,
  InvoicesResponse,
  UpcomingInvoice,
)
from ...models.api.common import RESOURCE_ERROR_RESPONSES
from ...models.core import User
from ...models.core.billing import BillingCustomer, BillingInvoice
from ...operations.providers.payment_provider import get_payment_provider

logger = get_logger(__name__)

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


@router.get(
  "/{org_id}",
  response_model=InvoicesResponse,
  summary="List Organization Invoices",
  description="Requires admin or owner role.",
  operation_id="listOrgInvoices",
  responses={**RESOURCE_ERROR_RESPONSES},
)
async def list_invoices(
  org_id: str,
  limit: int = Query(10, ge=1, le=100, description="Number of invoices to return"),
  current_user: User = Depends(get_current_user),
  db: Session = Depends(get_db_session),
  _rate_limit: None = Depends(billing_rate_limit_dependency),
):
  try:
    from ...models.core import OrgRole, OrgUser

    # Verify user is a member of the org
    membership = OrgUser.get_by_org_and_user(org_id, current_user.id, db)
    if not membership:
      raise HTTPException(
        status_code=403,
        detail="You are not a member of this organization",
      )

    # Only owners and admins can see invoices
    if membership.role not in [OrgRole.OWNER, OrgRole.ADMIN]:
      raise HTTPException(
        status_code=403,
        detail="Only owners and admins can view invoices",
      )

    db_invoices = (
      db.query(BillingInvoice)
      .filter(BillingInvoice.org_id == org_id)
      .order_by(BillingInvoice.created_at.desc())
      .limit(limit + 1)
      .all()
    )

    has_more = len(db_invoices) > limit
    db_invoices = db_invoices[:limit]

    invoices = []
    for inv in db_invoices:
      invoices.append(
        Invoice(
          id=inv.id,
          number=inv.invoice_number,
          status=inv.status,
          amount_due=inv.total_cents,
          amount_paid=inv.total_cents if inv.status == "paid" else 0,
          currency=inv.currency or "usd",
          created=inv.created_at.isoformat(),
          due_date=inv.due_date.isoformat() if inv.due_date else None,
          paid_at=inv.paid_at.isoformat() if inv.paid_at else None,
          invoice_pdf=inv.invoice_pdf,
          hosted_invoice_url=inv.hosted_invoice_url,
          line_items=[
            InvoiceLineItem(
              description=line.description,
              amount=line.amount_cents,
              quantity=line.quantity,
              period_start=(
                line.period_start.isoformat() if line.period_start else None
              ),
              period_end=line.period_end.isoformat() if line.period_end else None,
            )
            for line in inv.line_items
          ],
          subscription_id=inv.line_items[0].subscription_id if inv.line_items else None,
        )
      )

    return InvoicesResponse(
      invoices=invoices,
      total_count=len(invoices),
      has_more=has_more,
    )

  except HTTPException:
    raise
  except Exception as e:
    logger.error(f"Failed to list invoices: {e}", exc_info=True)
    raise HTTPException(status_code=500, detail="Failed to retrieve invoices")


@router.get(
  "/{org_id}/upcoming",
  response_model=UpcomingInvoice | None,
  summary="Get Organization Upcoming Invoice",
  description="Requires admin or owner role. Returns null if no billing activity yet.",
  operation_id="getOrgUpcomingInvoice",
  responses={**RESOURCE_ERROR_RESPONSES},
)
async def get_upcoming_invoice(
  org_id: str,
  current_user: User = Depends(get_current_user),
  db: Session = Depends(get_db_session),
  _rate_limit: None = Depends(billing_rate_limit_dependency),
):
  try:
    from ...models.core import OrgRole, OrgUser

    # Verify user is a member of the org
    membership = OrgUser.get_by_org_and_user(org_id, current_user.id, db)
    if not membership:
      raise HTTPException(
        status_code=403,
        detail="You are not a member of this organization",
      )

    # Only owners and admins can see upcoming invoices
    if membership.role not in [OrgRole.OWNER, OrgRole.ADMIN]:
      raise HTTPException(
        status_code=403,
        detail="Only owners and admins can view upcoming invoices",
      )

    customer = BillingCustomer.get_or_create(org_id, db)

    if not customer.stripe_customer_id:
      return None

    provider = get_payment_provider("stripe")
    upcoming = provider.get_upcoming_invoice(customer.stripe_customer_id)

    if not upcoming:
      return None

    return UpcomingInvoice(
      amount_due=upcoming["amount_due"],
      currency=upcoming["currency"],
      period_start=datetime.fromtimestamp(upcoming["period_start"]).isoformat(),
      period_end=datetime.fromtimestamp(upcoming["period_end"]).isoformat(),
      line_items=[
        InvoiceLineItem(
          description=line["description"],
          amount=line["amount"],
          quantity=line["quantity"],
          period_start=(
            datetime.fromtimestamp(line["period_start"]).isoformat()
            if line["period_start"]
            else None
          ),
          period_end=(
            datetime.fromtimestamp(line["period_end"]).isoformat()
            if line["period_end"]
            else None
          ),
        )
        for line in upcoming["lines"]
      ],
      subscription_id=upcoming["subscription"],
    )

  except HTTPException:
    raise
  except Exception as e:
    logger.error(f"Failed to get upcoming invoice: {e}", exc_info=True)
    raise HTTPException(status_code=500, detail="Failed to retrieve upcoming invoice")
