from datetime import date
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy import func, select
from sqlalchemy.orm import Session

from app.api.workspace import get_verified_current_user
from app.core.permissions import Permission
from app.db.session import get_db
from app.models.expense_income import Expense, OtherIncome
from app.models.payroll import PayrollRun
from app.models.purchase import Purchase
from app.models.sale import Sale
from app.models.user import User
from app.schemas.report import ReportFilters
from app.services import reports
from app.services.rbac import require_permission

router = APIRouter(tags=["Reports"])


def context(db: Session, user: User, business_id: UUID, filters: ReportFilters):
    try:
        filters.validate_range()
    except ValueError as error:
        raise HTTPException(422, str(error))
    member = require_permission(db, user, business_id, Permission.MANAGE_FINANCES)
    try:
        branches = reports.allowed_branch_ids(db, member, business_id, filters.branch_id)
    except PermissionError as error:
        raise HTTPException(403, str(error))
    return branches


def filters(branch_id: UUID | None = None, start_date: date | None = None, end_date: date | None = None, staff_id: UUID | None = None, product_id: UUID | None = None, customer_id: UUID | None = None, supplier_id: UUID | None = None):
    return ReportFilters(branch_id=branch_id, start_date=start_date, end_date=end_date, staff_id=staff_id, product_id=product_id, customer_id=customer_id, supplier_id=supplier_id)


@router.get("/api/businesses/{business_id}/reports/summary")
def summary(business_id: UUID, data: ReportFilters = Depends(filters), user: User = Depends(get_verified_current_user), db: Session = Depends(get_db)):
    branches = context(db, user, business_id, data)
    return {"sales": reports.sales_summary(db, business_id, branches, data), "purchases": reports.purchases_summary(db, business_id, branches, data), "profit_loss": reports.profit_loss(db, business_id, branches, data), "receivables": reports.receivables_aging(db, business_id, data)}


@router.get("/api/businesses/{business_id}/reports/profit-loss")
def profit_loss(business_id: UUID, data: ReportFilters = Depends(filters), user: User = Depends(get_verified_current_user), db: Session = Depends(get_db)):
    return reports.profit_loss(db, business_id, context(db, user, business_id, data), data)


@router.get("/api/businesses/{business_id}/reports/sales")
def sales(business_id: UUID, data: ReportFilters = Depends(filters), user: User = Depends(get_verified_current_user), db: Session = Depends(get_db)):
    return reports.sales_summary(db, business_id, context(db, user, business_id, data), data)


@router.get("/api/businesses/{business_id}/reports/sales-products")
def sales_products(business_id: UUID, data: ReportFilters = Depends(filters), user: User = Depends(get_verified_current_user), db: Session = Depends(get_db)):
    return reports.sales_by_product(db, business_id, context(db, user, business_id, data), data)


def sales_grouped(db: Session, business_id: UUID, branches, data: ReportFilters, column, label: str):
    query = select(column, func.count(Sale.id), func.coalesce(func.sum(Sale.total), 0)).where(Sale.business_id == business_id, Sale.lifecycle_status == "COMPLETED", *reports._dt_dates(Sale.sale_datetime, data)).group_by(column).order_by(func.sum(Sale.total).desc())
    if branches is not None: query = query.where(Sale.branch_id.in_(branches))
    if data.staff_id: query = query.where(Sale.created_by == data.staff_id)
    return [{label: row[0], "sale_count": row[1], "revenue": row[2]} for row in db.execute(query)]


@router.get("/api/businesses/{business_id}/reports/sales-staff")
def sales_staff(business_id: UUID, data: ReportFilters = Depends(filters), user: User = Depends(get_verified_current_user), db: Session = Depends(get_db)):
    return sales_grouped(db, business_id, context(db, user, business_id, data), data, Sale.created_by, "staff_id")


@router.get("/api/businesses/{business_id}/reports/sales-branches")
def sales_branches(business_id: UUID, data: ReportFilters = Depends(filters), user: User = Depends(get_verified_current_user), db: Session = Depends(get_db)):
    return sales_grouped(db, business_id, context(db, user, business_id, data), data, Sale.branch_id, "branch_id")


@router.get("/api/businesses/{business_id}/reports/purchases")
def purchases(business_id: UUID, data: ReportFilters = Depends(filters), user: User = Depends(get_verified_current_user), db: Session = Depends(get_db)):
    return reports.purchases_summary(db, business_id, context(db, user, business_id, data), data)


@router.get("/api/businesses/{business_id}/reports/receivables")
def receivables(business_id: UUID, data: ReportFilters = Depends(filters), user: User = Depends(get_verified_current_user), db: Session = Depends(get_db)):
    context(db, user, business_id, data)
    return reports.receivables_aging(db, business_id, data)


@router.get("/api/businesses/{business_id}/reports/payables")
def payables(business_id: UUID, data: ReportFilters = Depends(filters), user: User = Depends(get_verified_current_user), db: Session = Depends(get_db)):
    return reports.payables_summary(db, business_id, context(db, user, business_id, data), data)


@router.get("/api/businesses/{business_id}/reports/expenses")
def expenses(business_id: UUID, data: ReportFilters = Depends(filters), user: User = Depends(get_verified_current_user), db: Session = Depends(get_db)):
    branches = context(db, user, business_id, data); query = select(func.coalesce(func.sum(Expense.amount), 0)).where(Expense.business_id == business_id, Expense.status == "ACTIVE", *reports._dates(Expense.expense_date, data))
    if branches is not None: query = query.where(Expense.branch_id.in_(branches))
    return {"total": reports.scalar(db, query)}


@router.get("/api/businesses/{business_id}/reports/other-income")
def other_income(business_id: UUID, data: ReportFilters = Depends(filters), user: User = Depends(get_verified_current_user), db: Session = Depends(get_db)):
    branches = context(db, user, business_id, data); query = select(func.coalesce(func.sum(OtherIncome.amount), 0)).where(OtherIncome.business_id == business_id, OtherIncome.status == "ACTIVE", *reports._dates(OtherIncome.income_date, data))
    if branches is not None: query = query.where(OtherIncome.branch_id.in_(branches))
    return {"total": reports.scalar(db, query)}


@router.get("/api/businesses/{business_id}/reports/payroll")
def payroll(business_id: UUID, data: ReportFilters = Depends(filters), user: User = Depends(get_verified_current_user), db: Session = Depends(get_db)):
    context(db, user, business_id, data); query = select(func.coalesce(func.sum(PayrollRun.total_amount), 0)).where(PayrollRun.business_id == business_id, PayrollRun.status == "PAID")
    if data.start_date: query = query.where(PayrollRun.paid_at >= data.start_date)
    if data.end_date: query = query.where(PayrollRun.paid_at < date.fromordinal(data.end_date.toordinal() + 1))
    return {"total_paid": reports.scalar(db, query)}


@router.get("/api/businesses/{business_id}/reports/inventory-value")
def inventory_value(business_id: UUID, data: ReportFilters = Depends(filters), user: User = Depends(get_verified_current_user), db: Session = Depends(get_db)):
    return reports.inventory_value(db, business_id, context(db, user, business_id, data))


@router.get("/api/businesses/{business_id}/reports/stock-history")
def stock_history(business_id: UUID, data: ReportFilters = Depends(filters), user: User = Depends(get_verified_current_user), db: Session = Depends(get_db)):
    return reports.stock_history(db, business_id, context(db, user, business_id, data), data)
