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.expense_income import Expense, ExpenseCategory, OtherIncome, OtherIncomeCategory
from app.models.user import User
from app.schemas.expense_income import CategoryCreate, CategoryUpdate, ExpenseCreate, ExpenseUpdate, OtherIncomeCreate, OtherIncomeUpdate
from app.services.expense_income import cancel_entry, create_category, create_entry, entry, update_category, update_entry
from app.services.workspace import get_membership_for_business
router=APIRouter(tags=["Expenses and Other Income"])
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,"A category with that name already exists.")
def category_routes(prefix,cls):
    @router.post(prefix,status_code=201)
    def create(business_id:UUID,data:CategoryCreate,user:User=Depends(get_verified_current_user),db:Session=Depends(get_db)): access(db,user,business_id); return run(db,lambda:create_category(db,cls,business_id,data))
    @router.get(prefix)
    def listing(business_id:UUID,active:bool|None=None,user:User=Depends(get_verified_current_user),db:Session=Depends(get_db)):
        access(db,user,business_id); q=select(cls).where(cls.business_id==business_id).order_by(cls.name); return list(db.scalars(q if active is None else q.where(cls.is_active==active)))
    @router.patch(prefix+"/{category_id}")
    def update(business_id:UUID,category_id:UUID,data:CategoryUpdate,user:User=Depends(get_verified_current_user),db:Session=Depends(get_db)): access(db,user,business_id); return run(db,lambda:update_category(db,cls,business_id,category_id,data))
def entry_routes(prefix,cls,catcls,schema,update_schema,date_field,payment=False):
    @router.post(prefix,status_code=201)
    def create(business_id:UUID,data:schema,user:User=Depends(get_verified_current_user),db:Session=Depends(get_db)): access(db,user,business_id); return run(db,lambda:create_entry(db,cls,catcls,business_id,user.id,data))
    @router.get(prefix)
    def listing(business_id:UUID,category_id:UUID|None=None,branch_id:UUID|None=None,status:str|None=None,payment_method:str|None=None,start_date:date|None=None,end_date:date|None=None,user:User=Depends(get_verified_current_user),db:Session=Depends(get_db)):
        access(db,user,business_id); rows=list(db.scalars(select(cls).where(cls.business_id==business_id).order_by(cls.created_at.desc())))
        return [x for x in rows if (not category_id or x.category_id==category_id) and (not branch_id or x.branch_id==branch_id) and (not status or x.status==status) and (not payment or not payment_method or x.payment_method==payment_method) and (not start_date or getattr(x,date_field)>=start_date) and (not end_date or getattr(x,date_field)<=end_date)]
    @router.get(prefix+"/{entry_id}")
    def detail(business_id:UUID,entry_id:UUID,user:User=Depends(get_verified_current_user),db:Session=Depends(get_db)): access(db,user,business_id); return run(db,lambda:entry(db,cls,business_id,entry_id))
    @router.patch(prefix+"/{entry_id}")
    def update(business_id:UUID,entry_id:UUID,data:update_schema,user:User=Depends(get_verified_current_user),db:Session=Depends(get_db)): access(db,user,business_id); return run(db,lambda:update_entry(db,cls,catcls,business_id,entry_id,data))
    @router.post(prefix+"/{entry_id}/cancel")
    def cancel(business_id:UUID,entry_id:UUID,user:User=Depends(get_verified_current_user),db:Session=Depends(get_db)): access(db,user,business_id); return run(db,lambda:cancel_entry(db,cls,business_id,entry_id))
category_routes('/api/businesses/{business_id}/expense-categories',ExpenseCategory)
category_routes('/api/businesses/{business_id}/other-income-categories',OtherIncomeCategory)
entry_routes('/api/businesses/{business_id}/expenses',Expense,ExpenseCategory,ExpenseCreate,ExpenseUpdate,'expense_date',True)
entry_routes('/api/businesses/{business_id}/other-income',OtherIncome,OtherIncomeCategory,OtherIncomeCreate,OtherIncomeUpdate,'income_date',False)
