"""Domain entities.

These are plain dataclasses describing the shape of the business objects,
independent of Django's ORM. The infrastructure layer's Django models are
the actual persistence mechanism; these dataclasses are what the
application layer/use cases reason about and what repository interfaces
return. For this project the Django models double as adequate entities in
many read paths (returned directly by repositories) but the dataclasses
below document the intended shape and are used for pure-domain logic such
as the monthly report row builder.
"""
from __future__ import annotations

import datetime
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional


class LeaveType(str, Enum):
    DAILY = "daily"
    HOURLY = "hourly"


class LeaveCategory(str, Enum):
    ANNUAL = "annual"
    SICK = "sick"
    UNPAID = "unpaid"


class LeaveStatus(str, Enum):
    PENDING = "pending"
    APPROVED = "approved"
    REJECTED = "rejected"


@dataclass
class UserEntity:
    id: Optional[int]
    personnel_code: str
    name: Optional[str]
    is_admin: bool = False

    @property
    def has_name(self) -> bool:
        return bool(self.name)


@dataclass
class AttendanceEntity:
    id: Optional[int]
    user_id: int
    date: datetime.date
    check_in: Optional[datetime.time] = None
    check_out: Optional[datetime.time] = None
    is_default_checkout: bool = False
    tasks_note: Optional[str] = None

    @property
    def worked_minutes(self) -> Optional[int]:
        if self.check_in is None or self.check_out is None:
            return None
        today = datetime.date.today()
        dt_in = datetime.datetime.combine(today, self.check_in)
        dt_out = datetime.datetime.combine(today, self.check_out)
        return abs(int((dt_out - dt_in).total_seconds() // 60))

    @property
    def worked_hours_formatted(self) -> Optional[str]:
        minutes = self.worked_minutes
        if minutes is None:
            return None
        from domain.value_objects import format_minutes_as_hm

        return format_minutes_as_hm(minutes)


@dataclass
class HolidayEntity:
    id: Optional[int]
    date: datetime.date
    title: str
    description: Optional[str] = None


@dataclass
class WorkScheduleEntity:
    id: Optional[int]
    date: Optional[datetime.date]
    standard_check_in: datetime.time
    standard_check_out: datetime.time


@dataclass
class LeaveRequestEntity:
    id: Optional[int]
    user_id: int
    date: datetime.date
    type: LeaveType
    category: LeaveCategory
    start_time: Optional[datetime.time] = None
    end_time: Optional[datetime.time] = None
    reason: Optional[str] = None
    status: LeaveStatus = LeaveStatus.PENDING
    reviewed_by_id: Optional[int] = None
    reviewed_at: Optional[datetime.datetime] = None


@dataclass
class MonthlyReportRow:
    date: datetime.date
    jalali_date: str
    check_in: Optional[datetime.time]
    check_out: Optional[datetime.time]
    is_default_checkout: bool
    worked: Optional[str]
    tasks_note: Optional[str]
    is_holiday: bool
    holiday_title: Optional[str]
    leaves: list = field(default_factory=list)
    missing: bool = False
    standard_check_in: Optional[datetime.time] = None
    standard_check_out: Optional[datetime.time] = None
    late: Optional[str] = None
    overtime: Optional[str] = None


@dataclass
class MonthlyReport:
    rows: list
    monthly_total: str
