"""
Time & Attendance - Domain Entities

مدیریت شیفت، تایم‌شیت و حضور و غیاب.
"""
from dataclasses import dataclass, field
from datetime import date, datetime, time, timedelta
from decimal import Decimal
from typing import Optional, List
from uuid import UUID

from shared.base_classes.entity import TenantEntity


class ScheduleType:
    """انواع برنامه کاری."""
    STANDARD = "STANDARD"
    SHIFT = "SHIFT"
    FLEXIBLE = "FLEXIBLE"
    COMPRESSED = "COMPRESSED"
    REMOTE = "REMOTE"


class AttendanceStatus:
    """وضعیت حضور."""
    PRESENT = "PRESENT"
    ABSENT = "ABSENT"
    LATE = "LATE"
    EARLY_DEPARTURE = "EARLY_DEPARTURE"
    ON_LEAVE = "ON_LEAVE"
    HOLIDAY = "HOLIDAY"
    REMOTE = "REMOTE"
    BUSINESS_TRIP = "BUSINESS_TRIP"


class TimesheetStatus:
    """وضعیت تایم‌شیت."""
    DRAFT = "DRAFT"
    SUBMITTED = "SUBMITTED"
    APPROVED = "APPROVED"
    REJECTED = "REJECTED"
    REVISED = "REVISED"


@dataclass
class WorkSchedule(TenantEntity):
    """
    برنامه کاری.

    Rules:
    - ساعت پایان باید بعد از ساعت شروع باشد
    - حداکثر ساعت کاری روزانه ۱۶ ساعت
    """

    name: str = ""
    code: str = ""
    schedule_type: str = ScheduleType.STANDARD
    start_time: Optional[time] = None
    end_time: Optional[time] = None
    break_duration_minutes: int = 60
    working_days: list = field(default_factory=lambda: [0, 1, 2, 3, 4])  # شنبه تا چهارشنبه
    daily_hours: Decimal = Decimal("8.0")
    weekly_hours: Decimal = Decimal("44.0")
    is_night_shift: bool = False
    overtime_threshold_daily: Decimal = Decimal("8.0")
    overtime_threshold_weekly: Decimal = Decimal("44.0")
    is_active: bool = True
    metadata: dict = field(default_factory=dict)

    def validate(self) -> None:
        if not self.name:
            raise ValueError("نام برنامه کاری الزامی است")
        if not self.code:
            raise ValueError("کد برنامه کاری الزامی است")
        if self.daily_hours > 16:
            raise ValueError("ساعت کاری روزانه نمی‌تواند بیش از ۱۶ ساعت باشد")


@dataclass
class ShiftPattern(TenantEntity):
    """
    الگوی شیفت - تعریف دوره‌های تکرارشونده شیفت.

    Rules:
    - تعداد روزهای دوره باید مثبت باشد
    """

    name: str = ""
    code: str = ""
    cycle_days: int = 7
    shifts: list = field(default_factory=list)  # [{"day": 0, "schedule_id": "..."}, ...]
    is_active: bool = True

    def validate(self) -> None:
        if not self.name:
            raise ValueError("نام الگوی شیفت الزامی است")
        if self.cycle_days <= 0:
            raise ValueError("تعداد روزهای دوره باید مثبت باشد")


@dataclass
class Timesheet(TenantEntity):
    """
    تایم‌شیت - ثبت ساعات کار.

    Rules:
    - فقط Draft قابل ویرایش
    - Submit شده قابل Approve/Reject
    """

    employee_id: UUID = field(default_factory=lambda: None)
    period_start: Optional[date] = None
    period_end: Optional[date] = None
    status: str = TimesheetStatus.DRAFT
    total_regular_hours: Decimal = Decimal("0")
    total_overtime_hours: Decimal = Decimal("0")
    total_working_days: int = 0
    submitted_at: Optional[datetime] = None
    approved_at: Optional[datetime] = None
    approved_by: Optional[UUID] = None
    rejection_reason: str = ""
    notes: str = ""
    metadata: dict = field(default_factory=dict)

    def validate(self) -> None:
        if not self.employee_id:
            raise ValueError("شناسه کارمند الزامی است")
        if not self.period_start or not self.period_end:
            raise ValueError("دوره تایم‌شیت الزامی است")
        if self.period_end < self.period_start:
            raise ValueError("تاریخ پایان دوره نمی‌تواند قبل از شروع باشد")

    def can_submit(self) -> bool:
        return self.status == TimesheetStatus.DRAFT

    def submit(self) -> None:
        if not self.can_submit():
            raise ValueError("فقط تایم‌شیت‌های پیش‌نویس قابل ارسال هستند")
        self.status = TimesheetStatus.SUBMITTED
        self.submitted_at = datetime.utcnow()
        self.mark_updated()

    def approve(self, approver_id: UUID) -> None:
        if self.status != TimesheetStatus.SUBMITTED:
            raise ValueError("فقط تایم‌شیت‌های ارسال‌شده قابل تأیید هستند")
        self.status = TimesheetStatus.APPROVED
        self.approved_at = datetime.utcnow()
        self.approved_by = approver_id
        self.mark_updated()

    def reject(self, reason: str) -> None:
        if self.status != TimesheetStatus.SUBMITTED:
            raise ValueError("فقط تایم‌شیت‌های ارسال‌شده قابل رد هستند")
        self.status = TimesheetStatus.REJECTED
        self.rejection_reason = reason
        self.mark_updated()


@dataclass
class AttendanceRecord(TenantEntity):
    """
    رکورد حضور و غیاب.

    Rules:
    - ساعت خروج باید بعد از ساعت ورود باشد
    - هر کارمند حداکثر یک رکورد در هر روز
    """

    employee_id: UUID = field(default_factory=lambda: None)
    attendance_date: Optional[date] = None
    check_in: Optional[datetime] = None
    check_out: Optional[datetime] = None
    status: str = AttendanceStatus.PRESENT
    scheduled_start: Optional[time] = None
    scheduled_end: Optional[time] = None
    late_minutes: int = 0
    early_departure_minutes: int = 0
    overtime_minutes: int = 0
    break_minutes: int = 0
    effective_hours: Decimal = Decimal("0")
    source: str = "MANUAL"  # MANUAL, BIOMETRIC, GPS, MOBILE
    location_id: Optional[UUID] = None
    notes: str = ""
    metadata: dict = field(default_factory=dict)

    def validate(self) -> None:
        if not self.employee_id:
            raise ValueError("شناسه کارمند الزامی است")
        if not self.attendance_date:
            raise ValueError("تاریخ حضور الزامی است")
        if self.check_in and self.check_out and self.check_out <= self.check_in:
            raise ValueError("ساعت خروج باید بعد از ساعت ورود باشد")

    def calculate_effective_hours(self) -> Decimal:
        """محاسبه ساعات مؤثر."""
        if not self.check_in or not self.check_out:
            return Decimal("0")
        diff = self.check_out - self.check_in
        total_minutes = diff.total_seconds() / 60
        effective_minutes = total_minutes - self.break_minutes
        return Decimal(str(round(effective_minutes / 60, 2)))
