from datetime import date
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.database import get_db
from app.core.dependencies import CurrentUser, require_role
from app.models.time_entry import EntryStatus
from app.models.user import User, UserRole
from app.schemas.time_entry import (
    BalanceResponse,
    ManualEntryCreate,
    RejectRequest,
    StampInRequest,
    StampOutRequest,
    TimeEntryListResponse,
    TimeEntryOut,
    TimeEntryUpdate,
    TimeEntryWithWarnings,
    WorkScheduleCreate,
    WorkScheduleOut,
)
from app.services.time_service import time_service

router = APIRouter(prefix="/time", tags=["Zeiterfassung"])

_manager_roles = (UserRole.MANAGER, UserRole.HR, UserRole.COMPANY_ADMIN, UserRole.SUPER_ADMIN)


# ── Stempeluhr ────────────────────────────────────────────────────────────────

@router.post("/stamp-in", response_model=TimeEntryWithWarnings, status_code=201)
async def stamp_in(
    data: StampInRequest,
    current_user: CurrentUser,
    db: AsyncSession = Depends(get_db),
):
    """Einstempeln – startet einen neuen Zeiterfassungseintrag."""
    entry, warnings = await time_service.stamp_in(current_user, data, db)
    await db.commit()
    return TimeEntryWithWarnings(entry=TimeEntryOut.model_validate(entry), warnings=warnings)


@router.post("/stamp-out", response_model=TimeEntryWithWarnings)
async def stamp_out(
    data: StampOutRequest,
    current_user: CurrentUser,
    db: AsyncSession = Depends(get_db),
):
    """Ausstempeln – schließt den offenen Zeiterfassungseintrag."""
    entry, warnings = await time_service.stamp_out(current_user, data.note, db)
    await db.commit()
    return TimeEntryWithWarnings(entry=TimeEntryOut.model_validate(entry), warnings=warnings)


@router.post("/break-start", response_model=TimeEntryOut)
async def break_start(
    current_user: CurrentUser,
    db: AsyncSession = Depends(get_db),
):
    """Pause beginnen."""
    entry = await time_service.break_start(current_user, db)
    await db.commit()
    return TimeEntryOut.model_validate(entry)


@router.post("/break-end", response_model=TimeEntryOut)
async def break_end(
    current_user: CurrentUser,
    db: AsyncSession = Depends(get_db),
):
    """Pause beenden."""
    entry = await time_service.break_end(current_user, db)
    await db.commit()
    return TimeEntryOut.model_validate(entry)


# ── Heute ─────────────────────────────────────────────────────────────────────

@router.get("/today", response_model=list[TimeEntryOut])
async def get_today(
    current_user: CurrentUser,
    db: AsyncSession = Depends(get_db),
):
    """Alle Einträge des heutigen Tages für den aktuellen Benutzer."""
    entries = await time_service.get_today(current_user, db)
    return [TimeEntryOut.model_validate(e) for e in entries]


# ── Einträge ──────────────────────────────────────────────────────────────────

@router.get("/entries", response_model=TimeEntryListResponse)
async def list_entries(
    current_user: CurrentUser,
    user_id: UUID | None = Query(None),
    date_from: date | None = Query(None),
    date_to: date | None = Query(None),
    status: EntryStatus | None = Query(None),
    skip: int = Query(0, ge=0),
    limit: int = Query(50, ge=1, le=200),
    db: AsyncSession = Depends(get_db),
):
    total, entries = await time_service.list_entries(
        current_user.company_id, current_user, db,
        user_id=user_id, date_from=date_from, date_to=date_to,
        status=status, skip=skip, limit=limit,
    )
    return TimeEntryListResponse(total=total, items=[TimeEntryOut.model_validate(e) for e in entries])


@router.post("/entries", response_model=TimeEntryWithWarnings, status_code=201)
async def create_manual_entry(
    data: ManualEntryCreate,
    current_user: CurrentUser,
    db: AsyncSession = Depends(get_db),
):
    """Manuellen Zeiterfassungseintrag anlegen."""
    entry, warnings = await time_service.create_manual(data, current_user, db)
    await db.commit()
    return TimeEntryWithWarnings(entry=TimeEntryOut.model_validate(entry), warnings=warnings)


@router.patch("/entries/{entry_id}", response_model=TimeEntryOut)
async def update_entry(
    entry_id: UUID,
    data: TimeEntryUpdate,
    current_user: CurrentUser,
    db: AsyncSession = Depends(get_db),
):
    """Zeiterfassungseintrag korrigieren."""
    entry = await time_service.update_entry(entry_id, data, current_user, db)
    await db.commit()
    return TimeEntryOut.model_validate(entry)


@router.post("/entries/{entry_id}/approve", response_model=TimeEntryOut)
async def approve_entry(
    entry_id: UUID,
    current_user: User = require_role(*_manager_roles),
    db: AsyncSession = Depends(get_db),
):
    """Zeiterfassungseintrag genehmigen."""
    entry = await time_service.approve_entry(entry_id, current_user, db)
    await db.commit()
    return TimeEntryOut.model_validate(entry)


@router.post("/entries/{entry_id}/reject", response_model=TimeEntryOut)
async def reject_entry(
    entry_id: UUID,
    data: RejectRequest,
    current_user: User = require_role(*_manager_roles),
    db: AsyncSession = Depends(get_db),
):
    """Zeiterfassungseintrag ablehnen."""
    entry = await time_service.reject_entry(entry_id, current_user, data.rejection_note, db)
    await db.commit()
    return TimeEntryOut.model_validate(entry)


@router.delete("/entries/{entry_id}", status_code=204)
async def delete_entry(
    entry_id: UUID,
    current_user: CurrentUser,
    db: AsyncSession = Depends(get_db),
):
    """Zeiteintrag löschen. Mitarbeiter: nur eigene offene/ausstehende Einträge. Manager: alle außer genehmigten (außer HR/Admin)."""
    await time_service.delete_entry(entry_id, current_user, db)
    await db.commit()


# ── Überstundenkonto ──────────────────────────────────────────────────────────

@router.get("/balance/me", response_model=BalanceResponse)
async def get_own_balance(
    current_user: CurrentUser,
    period_start: date | None = Query(None),
    period_end: date | None = Query(None),
    db: AsyncSession = Depends(get_db),
):
    """Eigenes Überstundenkonto."""
    return await time_service.get_balance(current_user.id, current_user, db, period_start, period_end)


@router.get("/balance/{user_id}", response_model=BalanceResponse)
async def get_balance(
    user_id: UUID,
    current_user: CurrentUser,
    period_start: date | None = Query(None),
    period_end: date | None = Query(None),
    db: AsyncSession = Depends(get_db),
):
    """Überstundenkonto für einen Benutzer."""
    if user_id != current_user.id:
        if current_user.role == UserRole.EMPLOYEE:
            raise HTTPException(status_code=403, detail="Keine Berechtigung.")
        target_user = await db.get(User, user_id)
        if target_user is None or target_user.company_id != current_user.company_id:
            raise HTTPException(status_code=404, detail="Mitarbeiter nicht gefunden.")
    return await time_service.get_balance(user_id, current_user, db, period_start, period_end)


# ── Arbeitspläne ──────────────────────────────────────────────────────────────

@router.get("/schedules", response_model=list[WorkScheduleOut])
async def list_schedules(
    current_user: User = require_role(*_manager_roles),
    db: AsyncSession = Depends(get_db),
):
    schedules = await time_service.list_work_schedules(current_user.company_id, db)
    return [WorkScheduleOut.model_validate(s) for s in schedules]


@router.post("/schedules", response_model=WorkScheduleOut, status_code=201)
async def create_schedule(
    data: WorkScheduleCreate,
    current_user: User = require_role(UserRole.COMPANY_ADMIN, UserRole.SUPER_ADMIN),
    db: AsyncSession = Depends(get_db),
):
    schedule = await time_service.create_work_schedule(current_user.company_id, data, db)
    await db.commit()
    return WorkScheduleOut.model_validate(schedule)


@router.patch("/schedules/{schedule_id}", response_model=WorkScheduleOut)
async def update_schedule(
    schedule_id: UUID,
    data: WorkScheduleCreate,
    current_user: User = require_role(UserRole.COMPANY_ADMIN, UserRole.SUPER_ADMIN),
    db: AsyncSession = Depends(get_db),
):
    from sqlalchemy import select as sa_select
    from app.models.work_schedule import WorkSchedule
    schedule = await db.scalar(
        sa_select(WorkSchedule).where(
            WorkSchedule.id == schedule_id,
            WorkSchedule.company_id == current_user.company_id,
        )
    )
    if not schedule:
        from fastapi import HTTPException
        raise HTTPException(status_code=404, detail="Arbeitsplan nicht gefunden")
    for field, value in data.model_dump().items():
        setattr(schedule, field, value)
    await db.commit()
    return WorkScheduleOut.model_validate(schedule)


@router.delete("/schedules/{schedule_id}", status_code=204)
async def delete_schedule(
    schedule_id: UUID,
    current_user: User = require_role(UserRole.COMPANY_ADMIN, UserRole.SUPER_ADMIN),
    db: AsyncSession = Depends(get_db),
):
    from sqlalchemy import select as sa_select
    from app.models.work_schedule import WorkSchedule
    schedule = await db.scalar(
        sa_select(WorkSchedule).where(
            WorkSchedule.id == schedule_id,
            WorkSchedule.company_id == current_user.company_id,
        )
    )
    if not schedule:
        from fastapi import HTTPException
        raise HTTPException(status_code=404, detail="Arbeitsplan nicht gefunden")
    await db.delete(schedule)
    await db.commit()
