"""
Billing & Payment API Endpoints
"""
from fastapi import APIRouter, Depends, HTTPException, status, Query, Request
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from pydantic import BaseModel
from typing import Optional, List
from datetime import datetime, date
from decimal import Decimal

from app.database import get_db
from app.auth.dependencies import get_current_user, get_current_admin
from app.models.user import User
from app.models.invoice import Invoice, InvoiceStatus
from app.models.subscription import Subscription
from app.config import settings

router = APIRouter()


# Request/Response Models
class InvoiceResponse(BaseModel):
    id: int
    client_id: int
    invoice_number: str
    invoice_date: date
    due_date: date
    billing_period_start: date
    billing_period_end: date
    subtotal: float
    discount_amount: float
    tax_rate: float
    tax_amount: float
    total_amount: float
    amount_paid: float
    amount_due: float
    currency: str
    status: str
    line_items: list
    payment_method: Optional[str]
    paid_at: Optional[datetime]
    pdf_url: Optional[str]
    created_at: datetime

    class Config:
        from_attributes = True


class InvoiceListResponse(BaseModel):
    invoices: List[InvoiceResponse]
    total: int
    page: int
    page_size: int


class CreatePaymentRequest(BaseModel):
    invoice_id: int
    payment_method: str  # razorpay, stripe, bank_transfer
    return_url: Optional[str] = None


class PaymentResponse(BaseModel):
    payment_id: str
    order_id: str
    amount: float
    currency: str
    status: str
    payment_url: Optional[str] = None


@router.get("/invoices", response_model=InvoiceListResponse)
async def list_invoices(
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    status: Optional[str] = None,
    client_id: Optional[int] = None,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    List invoices (Admin sees all, clients see their own)
    """
    query = select(Invoice)

    # Non-admins can only see their own client's invoices
    if not current_user.is_admin:
        query = query.where(Invoice.client_id == current_user.client_id)
    elif client_id:
        query = query.where(Invoice.client_id == client_id)

    # Apply filters
    if status:
        query = query.where(Invoice.status == status)

    # Get total count
    count_query = select(func.count()).select_from(query.subquery())
    total = await db.scalar(count_query)

    # Apply pagination
    query = query.offset((page - 1) * page_size).limit(page_size)
    query = query.order_by(Invoice.created_at.desc())

    result = await db.execute(query)
    invoices = result.scalars().all()

    return InvoiceListResponse(
        invoices=[InvoiceResponse(
            id=inv.id,
            client_id=inv.client_id,
            invoice_number=inv.invoice_number,
            invoice_date=inv.invoice_date,
            due_date=inv.due_date,
            billing_period_start=inv.billing_period_start,
            billing_period_end=inv.billing_period_end,
            subtotal=float(inv.subtotal),
            discount_amount=float(inv.discount_amount or 0),
            tax_rate=float(inv.tax_rate or 18),
            tax_amount=float(inv.tax_amount),
            total_amount=float(inv.total_amount),
            amount_paid=float(inv.amount_paid or 0),
            amount_due=float(inv.amount_due),
            currency=inv.currency,
            status=inv.status,
            line_items=inv.line_items or [],
            payment_method=inv.payment_method,
            paid_at=inv.paid_at,
            pdf_url=inv.pdf_url,
            created_at=inv.created_at
        ) for inv in invoices],
        total=total,
        page=page,
        page_size=page_size
    )


@router.get("/invoices/{invoice_id}", response_model=InvoiceResponse)
async def get_invoice(
    invoice_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    Get a specific invoice
    """
    result = await db.execute(select(Invoice).where(Invoice.id == invoice_id))
    invoice = result.scalar_one_or_none()

    if not invoice:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Invoice not found"
        )

    # Check permissions
    if not current_user.is_admin and current_user.client_id != invoice.client_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Access denied"
        )

    return InvoiceResponse(
        id=invoice.id,
        client_id=invoice.client_id,
        invoice_number=invoice.invoice_number,
        invoice_date=invoice.invoice_date,
        due_date=invoice.due_date,
        billing_period_start=invoice.billing_period_start,
        billing_period_end=invoice.billing_period_end,
        subtotal=float(invoice.subtotal),
        discount_amount=float(invoice.discount_amount or 0),
        tax_rate=float(invoice.tax_rate or 18),
        tax_amount=float(invoice.tax_amount),
        total_amount=float(invoice.total_amount),
        amount_paid=float(invoice.amount_paid or 0),
        amount_due=float(invoice.amount_due),
        currency=invoice.currency,
        status=invoice.status,
        line_items=invoice.line_items or [],
        payment_method=invoice.payment_method,
        paid_at=invoice.paid_at,
        pdf_url=invoice.pdf_url,
        created_at=invoice.created_at
    )


@router.post("/create-payment", response_model=PaymentResponse)
async def create_payment(
    data: CreatePaymentRequest,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    Create a payment order for an invoice
    """
    result = await db.execute(select(Invoice).where(Invoice.id == data.invoice_id))
    invoice = result.scalar_one_or_none()

    if not invoice:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Invoice not found"
        )

    # Check permissions
    if not current_user.is_admin and current_user.client_id != invoice.client_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Access denied"
        )

    if invoice.status == InvoiceStatus.PAID:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invoice is already paid"
        )

    amount = float(invoice.amount_due) * 100  # Convert to paise for Razorpay

    if data.payment_method == "razorpay":
        # Create Razorpay order
        # In production, use razorpay SDK
        import secrets
        order_id = f"order_{secrets.token_hex(12)}"
        payment_id = f"pay_{secrets.token_hex(12)}"

        return PaymentResponse(
            payment_id=payment_id,
            order_id=order_id,
            amount=float(invoice.amount_due),
            currency=invoice.currency,
            status="created",
            payment_url=f"https://checkout.razorpay.com/{order_id}"
        )

    elif data.payment_method == "stripe":
        # Create Stripe payment intent
        import secrets
        payment_id = f"pi_{secrets.token_hex(12)}"
        order_id = f"cs_{secrets.token_hex(12)}"

        return PaymentResponse(
            payment_id=payment_id,
            order_id=order_id,
            amount=float(invoice.amount_due),
            currency=invoice.currency,
            status="created",
            payment_url=f"https://checkout.stripe.com/{order_id}"
        )

    else:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid payment method"
        )


@router.post("/verify-payment")
async def verify_payment(
    request: Request,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    Verify payment completion (called after payment gateway redirect)
    """
    body = await request.json()

    invoice_id = body.get("invoice_id")
    payment_id = body.get("payment_id")
    order_id = body.get("order_id")
    signature = body.get("signature")

    if not all([invoice_id, payment_id]):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Missing payment details"
        )

    result = await db.execute(select(Invoice).where(Invoice.id == invoice_id))
    invoice = result.scalar_one_or_none()

    if not invoice:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Invoice not found"
        )

    # TODO: Verify signature with payment gateway

    # Update invoice status
    invoice.status = InvoiceStatus.PAID
    invoice.amount_paid = invoice.amount_due
    invoice.payment_method = body.get("payment_method", "razorpay")
    invoice.payment_reference = payment_id
    invoice.paid_at = datetime.utcnow()

    await db.commit()

    return {
        "success": True,
        "message": "Payment verified successfully",
        "invoice_number": invoice.invoice_number
    }


@router.post("/webhooks/razorpay")
async def razorpay_webhook(
    request: Request,
    db: AsyncSession = Depends(get_db)
):
    """
    Handle Razorpay webhooks
    """
    body = await request.json()
    event = body.get("event")

    if event == "payment.captured":
        payment = body.get("payload", {}).get("payment", {}).get("entity", {})
        order_id = payment.get("order_id")

        # Find and update invoice
        result = await db.execute(
            select(Invoice).where(Invoice.razorpay_invoice_id == order_id)
        )
        invoice = result.scalar_one_or_none()

        if invoice:
            invoice.status = InvoiceStatus.PAID
            invoice.amount_paid = invoice.amount_due
            invoice.payment_method = "razorpay"
            invoice.payment_reference = payment.get("id")
            invoice.paid_at = datetime.utcnow()
            await db.commit()

    return {"status": "ok"}


@router.post("/webhooks/stripe")
async def stripe_webhook(
    request: Request,
    db: AsyncSession = Depends(get_db)
):
    """
    Handle Stripe webhooks
    """
    body = await request.json()
    event_type = body.get("type")

    if event_type == "checkout.session.completed":
        session = body.get("data", {}).get("object", {})
        invoice_id = session.get("metadata", {}).get("invoice_id")

        if invoice_id:
            result = await db.execute(
                select(Invoice).where(Invoice.id == int(invoice_id))
            )
            invoice = result.scalar_one_or_none()

            if invoice:
                invoice.status = InvoiceStatus.PAID
                invoice.amount_paid = invoice.amount_due
                invoice.payment_method = "stripe"
                invoice.payment_reference = session.get("payment_intent")
                invoice.paid_at = datetime.utcnow()
                await db.commit()

    return {"status": "ok"}


@router.get("/summary")
async def get_billing_summary(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    Get billing summary for current client
    """
    if not current_user.client_id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="No client associated with user"
        )

    # Get active subscriptions
    subs_result = await db.execute(
        select(Subscription)
        .where(Subscription.client_id == current_user.client_id)
        .where(Subscription.status == "active")
    )
    subscriptions = subs_result.scalars().all()

    # Get invoices
    inv_result = await db.execute(
        select(Invoice)
        .where(Invoice.client_id == current_user.client_id)
        .order_by(Invoice.created_at.desc())
        .limit(5)
    )
    recent_invoices = inv_result.scalars().all()

    # Calculate totals
    total_monthly = sum(float(s.price_monthly) for s in subscriptions)
    pending_amount = sum(
        float(inv.amount_due) - float(inv.amount_paid or 0)
        for inv in recent_invoices
        if inv.status in [InvoiceStatus.PENDING, InvoiceStatus.OVERDUE]
    )

    return {
        "active_subscriptions": len(subscriptions),
        "total_monthly_cost": total_monthly,
        "currency": "INR",
        "pending_payments": pending_amount,
        "recent_invoices": [{
            "id": inv.id,
            "invoice_number": inv.invoice_number,
            "amount": float(inv.total_amount),
            "status": inv.status,
            "due_date": inv.due_date
        } for inv in recent_invoices]
    }
