from datetime import date, timedelta from uuid import UUID from fastapi import APIRouter, Depends, Query from fastapi.responses import Response from sqlalchemy.ext.asyncio import AsyncSession from app.core.database import get_db from app.core.dependencies import CurrentUser, require_role from app.models.user import User, UserRole from app.schemas.report import ( AbsenceReport, CompanyDashboard, EmployeeDashboard, OvertimeReport, OvertimeReportDetailed, TeamDashboard, TimeReport, ) from app.services.report_service import report_service router = APIRouter(tags=["Dashboard & Reports"]) _manager_roles = (UserRole.MANAGER, UserRole.HR, UserRole.COMPANY_ADMIN, UserRole.SUPER_ADMIN) _admin_roles = (UserRole.COMPANY_ADMIN, UserRole.SUPER_ADMIN) # ── Dashboard ────────────────────────────────────────────────────────────────── @router.get("/dashboard/me", response_model=EmployeeDashboard) async def my_dashboard( current_user: CurrentUser, db: AsyncSession = Depends(get_db), ): """Mitarbeiter-Dashboard: eigene Stunden, Urlaub, Status heute.""" return await report_service.employee_dashboard(current_user, db) @router.get("/dashboard/team", response_model=TeamDashboard) async def team_dashboard( current_user: User = require_role(*_manager_roles), db: AsyncSession = Depends(get_db), ): """Team-Dashboard: Anwesenheit, ausstehende Genehmigungen.""" return await report_service.team_dashboard(current_user, db) @router.get("/dashboard/company", response_model=CompanyDashboard) async def company_dashboard( current_user: User = require_role(*_admin_roles), db: AsyncSession = Depends(get_db), ): """Unternehmens-Dashboard: Gesamtübersicht, Überstunden, kommende Abwesenheiten.""" return await report_service.company_dashboard(current_user, db) # ── Reports ──────────────────────────────────────────────────────────────────── def _default_date_from() -> date: today = date.today() return today.replace(day=1) def _default_date_to() -> date: return date.today() @router.get("/reports/time", response_model=TimeReport) async def time_report( current_user: CurrentUser, date_from: date = Query(default_factory=_default_date_from), date_to: date = Query(default_factory=_default_date_to), user_id: UUID | None = Query(None), db: AsyncSession = Depends(get_db), ): """Zeiterfassungsbericht (JSON). EMPLOYEE sieht nur eigene Einträge.""" return await report_service.time_report( current_user.company_id, current_user, db, date_from, date_to, user_id ) @router.get("/reports/absences", response_model=AbsenceReport) async def absence_report( current_user: CurrentUser, date_from: date = Query(default_factory=_default_date_from), date_to: date = Query(default_factory=_default_date_to), user_id: UUID | None = Query(None), db: AsyncSession = Depends(get_db), ): """Abwesenheitsbericht (JSON). EMPLOYEE sieht nur eigene Abwesenheiten.""" return await report_service.absence_report( current_user.company_id, current_user, db, date_from, date_to, user_id ) @router.get("/reports/overtime", response_model=OvertimeReport) async def overtime_report( current_user: CurrentUser, date_from: date = Query(default_factory=_default_date_from), date_to: date = Query(default_factory=_default_date_to), user_id: UUID | None = Query(None), db: AsyncSession = Depends(get_db), ): """Überstundenbericht (JSON). EMPLOYEE sieht nur eigene Daten.""" return await report_service.overtime_report( current_user.company_id, current_user, db, date_from, date_to, user_id ) @router.get("/reports/overtime/detail", response_model=OvertimeReportDetailed) async def overtime_report_detail( current_user: CurrentUser, date_from: date = Query(default_factory=_default_date_from), date_to: date = Query(default_factory=_default_date_to), user_id: UUID | None = Query(None), db: AsyncSession = Depends(get_db), ): """Erweiterter Überstundenbericht mit Wochen- und Tagesaufschlüsselung.""" return await report_service.overtime_report_detail( current_user.company_id, current_user, db, date_from, date_to, user_id ) # ── Export ───────────────────────────────────────────────────────────────────── @router.get("/reports/time/export") async def export_time_report( current_user: CurrentUser, date_from: date = Query(default_factory=_default_date_from), date_to: date = Query(default_factory=_default_date_to), user_id: UUID | None = Query(None), format: str = Query("csv", pattern="^(csv|xlsx|pdf)$"), db: AsyncSession = Depends(get_db), ): """Zeiterfassungsbericht als CSV, XLSX oder PDF herunterladen.""" report = await report_service.time_report( current_user.company_id, current_user, db, date_from, date_to, user_id ) filename = f"zeiterfassung_{date_from}_{date_to}" if format == "pdf": content = report_service.time_report_to_pdf(report) return Response(content=content, media_type="application/pdf", headers={"Content-Disposition": f"attachment; filename={filename}.pdf"}) if format == "xlsx": content = report_service.to_xlsx(report_service._time_rows_to_dicts(report.rows), sheet_name="Zeiterfassung") return Response(content=content, media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", headers={"Content-Disposition": f"attachment; filename={filename}.xlsx"}) content = report_service.to_csv(report_service._time_rows_to_dicts(report.rows)) return Response(content=content, media_type="text/csv; charset=utf-8", headers={"Content-Disposition": f"attachment; filename={filename}.csv"}) @router.get("/reports/absences/export") async def export_absence_report( current_user: CurrentUser, date_from: date = Query(default_factory=_default_date_from), date_to: date = Query(default_factory=_default_date_to), user_id: UUID | None = Query(None), format: str = Query("csv", pattern="^(csv|xlsx|pdf)$"), db: AsyncSession = Depends(get_db), ): """Abwesenheitsbericht als CSV, XLSX oder PDF herunterladen.""" report = await report_service.absence_report( current_user.company_id, current_user, db, date_from, date_to, user_id ) filename = f"abwesenheiten_{date_from}_{date_to}" if format == "pdf": content = report_service.absence_report_to_pdf(report) return Response(content=content, media_type="application/pdf", headers={"Content-Disposition": f"attachment; filename={filename}.pdf"}) if format == "xlsx": content = report_service.to_xlsx(report_service._absence_rows_to_dicts(report.rows), sheet_name="Abwesenheiten") return Response(content=content, media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", headers={"Content-Disposition": f"attachment; filename={filename}.xlsx"}) content = report_service.to_csv(report_service._absence_rows_to_dicts(report.rows)) return Response(content=content, media_type="text/csv; charset=utf-8", headers={"Content-Disposition": f"attachment; filename={filename}.csv"}) @router.get("/reports/overtime/export") async def export_overtime_report( current_user: CurrentUser, date_from: date = Query(default_factory=_default_date_from), date_to: date = Query(default_factory=_default_date_to), user_id: UUID | None = Query(None), format: str = Query("csv", pattern="^(csv|xlsx|pdf)$"), db: AsyncSession = Depends(get_db), ): """Überstundenbericht als CSV, XLSX oder PDF herunterladen (Detailansicht).""" detail = await report_service.overtime_report_detail( current_user.company_id, current_user, db, date_from, date_to, user_id ) filename = f"ueberstunden_{date_from}_{date_to}" if format == "pdf": content = report_service.overtime_detail_to_pdf(detail) return Response(content=content, media_type="application/pdf", headers={"Content-Disposition": f"attachment; filename={filename}.pdf"}) if format == "xlsx": content = report_service.to_xlsx(report_service._overtime_detail_to_dicts(detail), sheet_name="Überstunden") return Response(content=content, media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", headers={"Content-Disposition": f"attachment; filename={filename}.xlsx"}) content = report_service.to_csv(report_service._overtime_detail_to_dicts(detail)) return Response(content=content, media_type="text/csv; charset=utf-8", headers={"Content-Disposition": f"attachment; filename={filename}.csv"})