from fastapi import APIRouter, Depends, Query, UploadFile, File
from fastapi.responses import StreamingResponse
from typing import Optional
import io
from sqlalchemy.ext.asyncio import AsyncSession

from auth.dependencies import require_permission
from auth.models import TokenPayload
from crm.quotation_models import (
    NextNumberResponse,
    QuotationCreate,
    QuotationInDB,
    QuotationListResponse,
    QuotationUpdate,
)
from crm import quotations_service as svc
from database.postgres import get_pg_session
from shared.audit import log_action

router = APIRouter(prefix="/api/crm/quotations", tags=["crm-quotations"])


# IMPORTANT: Static paths must come BEFORE /{id} to avoid route collision in FastAPI

@router.get("/next-number", response_model=NextNumberResponse)
async def get_next_number(
    _user: TokenPayload = Depends(require_permission("crm", "view")),
):
    """Returns the next available quotation number (preview only — does not commit)."""
    next_num = await svc.get_next_number()
    return NextNumberResponse(next_number=next_num)


@router.get("/all", response_model=list[dict])
async def list_all_quotations(
    _user: TokenPayload = Depends(require_permission("crm", "view")),
):
    """Returns all quotations across all customers, each including customer_name."""
    return await svc.list_all_quotations()


@router.get("/customer/{customer_id}", response_model=QuotationListResponse)
async def list_quotations_for_customer(
    customer_id: str,
    _user: TokenPayload = Depends(require_permission("crm", "view")),
):
    quotations = await svc.list_quotations(customer_id)
    return QuotationListResponse(quotations=quotations, total=len(quotations))


@router.get("/{quotation_id}/pdf")
async def proxy_quotation_pdf(
    quotation_id: str,
    _user: TokenPayload = Depends(require_permission("crm", "view")),
):
    """Proxy the quotation PDF from Nextcloud to bypass browser cookie restrictions."""
    pdf_bytes = await svc.get_quotation_pdf_bytes(quotation_id)
    return StreamingResponse(
        io.BytesIO(pdf_bytes),
        media_type="application/pdf",
        headers={"Content-Disposition": "inline"},
    )


@router.get("/{quotation_id}", response_model=QuotationInDB)
async def get_quotation(
    quotation_id: str,
    _user: TokenPayload = Depends(require_permission("crm", "view")),
):
    return await svc.get_quotation(quotation_id)


@router.post("", response_model=QuotationInDB, status_code=201)
async def create_quotation(
    body: QuotationCreate,
    generate_pdf: bool = Query(False),
    _user: TokenPayload = Depends(require_permission("crm", "edit")),
    db: AsyncSession = Depends(get_pg_session),
):
    """
    Create a quotation. Pass ?generate_pdf=true to immediately generate and upload the PDF.
    """
    q = await svc.create_quotation(body, generate_pdf=generate_pdf)
    await log_action(db, _user.sub, _user.name or _user.email, "CREATE", "quotation",
                     str(q.id), q.quotation_number or str(q.id))
    return q


@router.put("/{quotation_id}", response_model=QuotationInDB)
async def update_quotation(
    quotation_id: str,
    body: QuotationUpdate,
    generate_pdf: bool = Query(False),
    _user: TokenPayload = Depends(require_permission("crm", "edit")),
    db: AsyncSession = Depends(get_pg_session),
):
    """
    Update a quotation. Pass ?generate_pdf=true to regenerate the PDF.
    """
    old = await svc.get_quotation(quotation_id)
    q = await svc.update_quotation(quotation_id, body, generate_pdf=generate_pdf)
    _SKIP = {"updated_at", "id", "items", "pdf_path"}
    changes = {
        k: {"old": getattr(old, k, None), "new": getattr(q, k, None)}
        for k in body.model_fields_set
        if k not in _SKIP and getattr(old, k, None) != getattr(q, k, None)
    }
    await log_action(db, _user.sub, _user.name or _user.email, "UPDATE", "quotation",
                     quotation_id, q.quotation_number or quotation_id, changes=changes or None)
    return q


@router.delete("/{quotation_id}", status_code=204)
async def delete_quotation(
    quotation_id: str,
    _user: TokenPayload = Depends(require_permission("crm", "edit")),
    db: AsyncSession = Depends(get_pg_session),
):
    q = await svc.get_quotation(quotation_id)
    await svc.delete_quotation(quotation_id)
    await log_action(db, _user.sub, _user.name or _user.email, "DELETE", "quotation",
                     quotation_id, q.quotation_number if q else quotation_id)


@router.post("/{quotation_id}/regenerate-pdf", response_model=QuotationInDB)
async def regenerate_pdf(
    quotation_id: str,
    _user: TokenPayload = Depends(require_permission("crm", "edit")),
):
    """Force PDF regeneration and re-upload to Nextcloud."""
    return await svc.regenerate_pdf(quotation_id)


@router.post("/{quotation_id}/legacy-pdf", response_model=QuotationInDB)
async def upload_legacy_pdf(
    quotation_id: str,
    file: UploadFile = File(...),
    _user: TokenPayload = Depends(require_permission("crm", "edit")),
):
    """Upload a PDF file for a legacy quotation and store its Nextcloud path."""
    pdf_bytes = await file.read()
    filename = file.filename or f"legacy-{quotation_id}.pdf"
    return await svc.upload_legacy_pdf(quotation_id, pdf_bytes, filename)
