"""Attendance use cases: checkout, default-checkout backfill, admin edit."""
from __future__ import annotations

import datetime

from domain.exceptions import AlreadyCheckedOutError, AttendanceNotFoundError, InvalidAttendanceEditError, NotCheckedInError
from domain.repositories import AttendanceRepository

DEFAULT_CHECKOUT_TIME = datetime.time(17, 30, 0)


class CheckOut:
    """Employee checks out for today.

    Only succeeds if today's Attendance exists, check_in is set, and
    check_out is not already set (idempotent guard).
    """

    def __init__(self, attendance_repo: AttendanceRepository):
        self.attendance_repo = attendance_repo

    def execute(self, user, tasks_note: str):
        today = datetime.date.today()
        attendance = self.attendance_repo.get_for_day(user.id, today)
        if attendance is None or not attendance.check_in:
            raise AttendanceNotFoundError("No check-in found for today; cannot check out.")
        if attendance.check_out:
            raise AlreadyCheckedOutError("Already checked out today.")

        attendance.check_out = datetime.datetime.now().time().replace(microsecond=0)
        attendance.is_default_checkout = False
        attendance.tasks_note = tasks_note
        self.attendance_repo.save(attendance)
        return attendance


class ApplyDefaultCheckoutForPastDays:
    """Scheduled use case: for past days where check_in is set but
    check_out is not, apply the default checkout time (17:30) and flag
    is_default_checkout=True. Intended to run once per day (management
    command / cron / celery beat)."""

    def __init__(self, attendance_repo: AttendanceRepository):
        self.attendance_repo = attendance_repo

    def execute(self) -> int:
        today = datetime.date.today()
        rows = self.attendance_repo.find_pending_default_checkout(before=today)
        count = 0
        for row in rows:
            row.check_out = DEFAULT_CHECKOUT_TIME
            row.is_default_checkout = True
            self.attendance_repo.save(row)
            count += 1
        return count


class AdminEditAttendance:
    """Admin manually sets/overwrites check_in/check_out/tasks_note for a
    given (user, date). Creates the row if missing (backfill). Always
    clears is_default_checkout on manual admin edit."""

    def __init__(self, attendance_repo: AttendanceRepository):
        self.attendance_repo = attendance_repo

    def execute(
        self,
        user_id: int,
        date: datetime.date,
        check_in: datetime.time | None,
        check_out: datetime.time | None,
        tasks_note: str | None,
    ):
        if check_in and check_out and check_out <= check_in:
            raise InvalidAttendanceEditError("check_out must be after check_in.")

        attendance = self.attendance_repo.get_or_create_for_day(user_id, date)
        attendance.check_in = check_in
        attendance.check_out = check_out
        attendance.tasks_note = tasks_note
        attendance.is_default_checkout = False
        self.attendance_repo.save(attendance)
        return attendance
