from datetime import date, timedelta
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException, 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/datev-monthly/export")
async def export_datev_monthly(
    current_user: CurrentUser,
    user_id: UUID,
    year: int = Query(..., ge=2000, le=2100),
    month: int = Query(..., ge=1, le=12),
    db: AsyncSession = Depends(get_db),
):
    """DATEV-Monatsblatt (Blanko-Layout) als PDF für Steuerberater-Übergabe.
    EMPLOYEE darf nur den eigenen Monat exportieren."""
    if current_user.role not in _manager_roles and user_id != current_user.id:
        raise HTTPException(403, "Nur eigenes Monatsblatt exportierbar")

    sheet = await report_service.datev_monthly_report(
        current_user.company_id, user_id, year, month, db
    )
    content = report_service.datev_monthly_report_to_pdf(sheet)
    filename = f"datev_stundenaufzeichnung_{sheet.user_name.replace(' ', '_')}_{year}_{month:02d}.pdf"
    return Response(content=content, media_type="application/pdf",
                    headers={"Content-Disposition": f"attachment; filename={filename}"})


@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"})
