from datetime import date
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy import select
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
from app.api.workspace import get_verified_current_user
from app.db.session import get_db
from app.models.quote import Quote, QuoteItem
from app.models.user import User
from app.schemas.quote import QuoteCreate, QuoteUpdate
from app.services.quotes import create_quote, effective_status, get_quote, transition_quote, update_quote, convert_quote
from app.services.workspace import get_membership_for_business

router = APIRouter(tags=["Quotes"])
def access(db, user, business_id):
    if not get_membership_for_business(db, user, business_id): raise HTTPException(404, "Business workspace not found.")
def run(db, fn):
    try: return fn()
    except LookupError as e: raise HTTPException(404, str(e))
    except ValueError as e: db.rollback(); raise HTTPException(422, str(e))
    except IntegrityError: db.rollback(); raise HTTPException(409, "Duplicate quote number.")
def view(db, quote):
    data = {column.name: getattr(quote, column.name) for column in Quote.__table__.columns}
    data["status"] = effective_status(quote)
    data["items"] = list(db.scalars(select(QuoteItem).where(QuoteItem.quote_id == quote.id)))
    return data
@router.post('/api/businesses/{business_id}/quotes', status_code=201)
def create(business_id: UUID, data: QuoteCreate, user: User=Depends(get_verified_current_user), db: Session=Depends(get_db)):
    access(db,user,business_id); return run(db, lambda: view(db, create_quote(db,business_id,user.id,data)))
@router.get('/api/businesses/{business_id}/quotes')
def listing(business_id: UUID, customer_id: UUID|None=None, branch_id: UUID|None=None, status: str|None=None, start_date: date|None=None, end_date: date|None=None, expired: bool|None=None, user: User=Depends(get_verified_current_user), db: Session=Depends(get_db)):
    access(db,user,business_id); quotes=list(db.scalars(select(Quote).where(Quote.business_id==business_id).order_by(Quote.created_at.desc())))
    def match(q):
        s=effective_status(q)
        return (not customer_id or q.customer_id==customer_id) and (not branch_id or q.branch_id==branch_id) and (not status or s==status) and (not start_date or q.issue_date>=start_date) and (not end_date or q.issue_date<=end_date) and (expired is None or (s=="EXPIRED")==expired)
    return [view(db,q) for q in quotes if match(q)]
@router.get('/api/businesses/{business_id}/quotes/{quote_id}')
def detail(business_id: UUID, quote_id: UUID, user: User=Depends(get_verified_current_user), db: Session=Depends(get_db)):
    access(db,user,business_id); return run(db,lambda:view(db,get_quote(db,business_id,quote_id)))
@router.patch('/api/businesses/{business_id}/quotes/{quote_id}')
def update(business_id: UUID, quote_id: UUID, data: QuoteUpdate, user: User=Depends(get_verified_current_user), db: Session=Depends(get_db)):
    access(db,user,business_id); return run(db,lambda:view(db,update_quote(db,business_id,quote_id,data)))
def action(target):
    def handler(business_id: UUID, quote_id: UUID, user: User=Depends(get_verified_current_user), db: Session=Depends(get_db)):
        access(db,user,business_id); return run(db,lambda:view(db,transition_quote(db,business_id,quote_id,target)))
    return handler
router.post('/api/businesses/{business_id}/quotes/{quote_id}/send')(action("SENT"))
router.post('/api/businesses/{business_id}/quotes/{quote_id}/accept')(action("ACCEPTED"))
router.post('/api/businesses/{business_id}/quotes/{quote_id}/reject')(action("REJECTED"))
@router.post('/api/businesses/{business_id}/quotes/{quote_id}/convert-to-invoice')
def convert(business_id: UUID, quote_id: UUID, user: User=Depends(get_verified_current_user), db: Session=Depends(get_db)):
    access(db,user,business_id)
    def go():
        quote, invoice = convert_quote(db,business_id,quote_id,user.id)
        return {"quote": view(db, quote), "invoice_id": invoice.id}
    return run(db, go)
