# app/modules/orders/routes/api/store_invoices.py
"""
Store invoice management endpoints.

Store Context: Uses token_store_id from JWT token (authenticated store API pattern).
The get_current_store_api dependency guarantees token_store_id is present.

Endpoints:
- GET /invoices - List store invoices
- GET /invoices/{invoice_id} - Get invoice details
- POST /invoices - Create invoice from order
- PUT /invoices/{invoice_id}/status - Update invoice status
- GET /invoices/{invoice_id}/pdf - Download invoice PDF
- POST /invoices/{invoice_id}/pdf - Generate/regenerate invoice PDF
- GET /invoices/settings - Get invoice settings
- POST /invoices/settings - Create invoice settings
- PUT /invoices/settings - Update invoice settings
- GET /invoices/stats - Get invoice statistics

Feature Requirements:
- invoice_lu: Basic Luxembourg invoicing (Essential tier)
- invoice_eu_vat: EU VAT support (Professional tier)
- invoice_bulk: Bulk invoicing (Business tier)
- accounting_export: Export to accounting software (Business tier)
"""

import logging
from pathlib import Path

from fastapi import APIRouter, Depends, Query
from fastapi.responses import FileResponse
from sqlalchemy.orm import Session

from app.api.deps import get_current_store_api, require_module_access
from app.core.database import get_db
from app.modules.billing.dependencies.feature_gate import RequireFeature
from app.modules.enums import FrontendType
from app.modules.orders.exceptions import (
    InvoicePDFNotFoundException,
)
from app.modules.orders.schemas import (
    InvoiceCreate,
    InvoiceListPaginatedResponse,
    InvoiceListResponse,
    InvoicePDFGeneratedResponse,
    InvoiceResponse,
    InvoiceStatsResponse,
    InvoiceStatusUpdate,
    StoreInvoiceSettingsCreate,
    StoreInvoiceSettingsResponse,
    StoreInvoiceSettingsUpdate,
)
from app.modules.orders.services.invoice_service import invoice_service
from app.modules.tenancy.schemas.auth import UserContext

store_invoices_router = APIRouter(
    prefix="/invoices",
    dependencies=[Depends(require_module_access("orders", FrontendType.STORE))],
)
logger = logging.getLogger(__name__)


# ============================================================================
# Invoice Settings
# ============================================================================


@store_invoices_router.get("/settings", response_model=StoreInvoiceSettingsResponse | None)
def get_invoice_settings(
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
    _: None = Depends(RequireFeature("invoice_lu")),
):
    """
    Get store invoice settings.

    Returns null if settings not yet configured.
    Requires: invoice_lu feature (Essential tier)
    """
    settings = invoice_service.get_settings(db, current_user.token_store_id)
    if settings:
        return StoreInvoiceSettingsResponse.model_validate(settings)
    return None


@store_invoices_router.post("/settings", response_model=StoreInvoiceSettingsResponse, status_code=201)
def create_invoice_settings(
    data: StoreInvoiceSettingsCreate,
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Create store invoice settings.

    Required before creating invoices. Sets merchant details,
    VAT number, invoice numbering preferences, and payment info.
    """
    settings = invoice_service.create_settings(
        db=db,
        store_id=current_user.token_store_id,
        data=data,
    )
    return StoreInvoiceSettingsResponse.model_validate(settings)


@store_invoices_router.put("/settings", response_model=StoreInvoiceSettingsResponse)
def update_invoice_settings(
    data: StoreInvoiceSettingsUpdate,
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Update store invoice settings.
    """
    settings = invoice_service.update_settings(
        db=db,
        store_id=current_user.token_store_id,
        data=data,
    )
    return StoreInvoiceSettingsResponse.model_validate(settings)


# ============================================================================
# Invoice Statistics
# ============================================================================


@store_invoices_router.get("/stats", response_model=InvoiceStatsResponse)
def get_invoice_stats(
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Get invoice statistics for the store.

    Returns:
    - total_invoices: Total number of invoices
    - total_revenue: Total revenue from issued/paid invoices (EUR)
    - draft_count: Number of draft invoices
    - paid_count: Number of paid invoices
    """
    stats = invoice_service.get_invoice_stats(db, current_user.token_store_id)
    return InvoiceStatsResponse(
        total_invoices=stats.get("total_invoices", 0),
        total_revenue_cents=stats.get("total_revenue_cents", 0),
        draft_count=stats.get("draft_count", 0),
        issued_count=stats.get("issued_count", 0),
        paid_count=stats.get("paid_count", 0),
        cancelled_count=stats.get("cancelled_count", 0),
    )


# ============================================================================
# Invoice CRUD
# ============================================================================


@store_invoices_router.get("", response_model=InvoiceListPaginatedResponse)
def list_invoices(
    page: int = Query(1, ge=1, description="Page number"),
    per_page: int = Query(20, ge=1, le=100, description="Items per page"),
    status: str | None = Query(None, description="Filter by status"),
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    List store invoices with pagination.

    Supports filtering by status: draft, issued, paid, cancelled
    """
    invoices, total = invoice_service.list_invoices(
        db=db,
        store_id=current_user.token_store_id,
        status=status,
        page=page,
        per_page=per_page,
    )

    # Build response with buyer name from snapshot
    items = []
    for inv in invoices:
        buyer_name = inv.buyer_details.get("name") if inv.buyer_details else None
        items.append(
            InvoiceListResponse(
                id=inv.id,
                invoice_number=inv.invoice_number,
                invoice_date=inv.invoice_date,
                status=inv.status,
                currency=inv.currency,
                total_cents=inv.total_cents,
                order_id=inv.order_id,
                buyer_name=buyer_name,
            )
        )

    pages = (total + per_page - 1) // per_page if total > 0 else 1

    return InvoiceListPaginatedResponse(
        items=items,
        total=total,
        page=page,
        per_page=per_page,
        pages=pages,
    )


@store_invoices_router.get("/{invoice_id}", response_model=InvoiceResponse)
def get_invoice(
    invoice_id: int,
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Get invoice details by ID.
    """
    invoice = invoice_service.get_invoice_or_raise(
        db=db,
        store_id=current_user.token_store_id,
        invoice_id=invoice_id,
    )
    return InvoiceResponse.model_validate(invoice)


@store_invoices_router.post("", response_model=InvoiceResponse, status_code=201)
def create_invoice(
    data: InvoiceCreate,
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Create an invoice from an order.

    Automatically:
    - Captures seller/buyer details snapshots
    - Calculates VAT based on buyer country and OSS settings
    - Generates invoice number
    """
    invoice = invoice_service.create_invoice_from_order(
        db=db,
        store_id=current_user.token_store_id,
        order_id=data.order_id,
        notes=data.notes,
    )
    return InvoiceResponse.model_validate(invoice)


@store_invoices_router.put("/{invoice_id}/status", response_model=InvoiceResponse)
def update_invoice_status(
    invoice_id: int,
    data: InvoiceStatusUpdate,
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Update invoice status.

    Valid statuses:
    - draft: Invoice created but not yet sent
    - issued: Invoice sent to customer
    - paid: Payment received
    - cancelled: Invoice cancelled

    Note: Cancelled invoices cannot be modified.
    """
    invoice = invoice_service.update_status(
        db=db,
        store_id=current_user.token_store_id,
        invoice_id=invoice_id,
        new_status=data.status,
    )
    return InvoiceResponse.model_validate(invoice)


# ============================================================================
# PDF Generation
# ============================================================================


@store_invoices_router.post("/{invoice_id}/pdf", response_model=InvoicePDFGeneratedResponse)
def generate_invoice_pdf(
    invoice_id: int,
    regenerate: bool = Query(False, description="Force regenerate if exists"),
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Generate PDF for an invoice.

    Set regenerate=true to force regeneration if PDF already exists.
    Returns the path to the generated PDF.
    """
    pdf_path = invoice_service.generate_pdf(
        db=db,
        store_id=current_user.token_store_id,
        invoice_id=invoice_id,
        force_regenerate=regenerate,
    )
    return InvoicePDFGeneratedResponse(pdf_path=pdf_path)


@store_invoices_router.get("/{invoice_id}/pdf")
def download_invoice_pdf(
    invoice_id: int,
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Download invoice PDF.

    Returns the PDF file for download.
    Generates PDF if not already generated.
    """
    # Check if PDF exists, generate if not
    pdf_path = invoice_service.get_pdf_path(
        db=db,
        store_id=current_user.token_store_id,
        invoice_id=invoice_id,
    )

    if not pdf_path:
        # Generate PDF
        pdf_path = invoice_service.generate_pdf(
            db=db,
            store_id=current_user.token_store_id,
            invoice_id=invoice_id,
        )

    # Verify file exists
    if not Path(pdf_path).exists():
        raise InvoicePDFNotFoundException(invoice_id)

    # Get invoice for filename
    invoice = invoice_service.get_invoice_or_raise(
        db=db,
        store_id=current_user.token_store_id,
        invoice_id=invoice_id,
    )

    filename = f"invoice-{invoice.invoice_number}.pdf"

    return FileResponse(
        path=pdf_path,
        media_type="application/pdf",
        filename=filename,
        headers={
            "Content-Disposition": f'attachment; filename="{filename}"'
        },
    )
