"""
HRM Use Cases - Time & Attendance and Payroll Operations.
"""
from dataclasses import dataclass
from decimal import Decimal
from uuid import uuid4

from ..dtos.hrm_dtos import (
    RecordAttendanceDTO,
    SubmitTimesheetDTO,
    AttendanceResponseDTO,
    SetSalaryDTO,
    CompensationResponseDTO,
    CreateBankAccountDTO,
    CreateWorkScheduleDTO,
)
from ...domain.entities.time_attendance import (
    AttendanceRecord,
    Timesheet,
    TimesheetStatus,
    WorkSchedule,
)
from ...domain.entities.payroll import CompensationRecord, BankAccount
from ...domain.repositories.interfaces import (
    IAttendanceRecordRepository,
    ITimesheetRepository,
    IWorkScheduleRepository,
    ICompensationRecordRepository,
    IBankAccountRepository,
)
from ...domain.exceptions.hrm_exceptions import TimesheetError, PayrollError


@dataclass
class RecordAttendanceUseCase:
    """Use Case - ثبت حضور و غیاب."""

    attendance_repo: IAttendanceRecordRepository

    def execute(self, dto: RecordAttendanceDTO, tenant_id=None) -> AttendanceResponseDTO:
        # Check for existing record
        existing = self.attendance_repo.find_by_employee_date(
            dto.employee_id, dto.attendance_date
        )
        if existing:
            # Update existing
            if dto.check_in:
                existing.check_in = dto.check_in
            if dto.check_out:
                existing.check_out = dto.check_out
            existing.source = dto.source
            existing.location_id = dto.location_id
            existing.effective_hours = existing.calculate_effective_hours()
            existing.mark_updated()
            saved = self.attendance_repo.save(existing)
        else:
            record = AttendanceRecord(
                id=uuid4(),
                tenant_id=tenant_id,
                employee_id=dto.employee_id,
                attendance_date=dto.attendance_date,
                check_in=dto.check_in,
                check_out=dto.check_out,
                source=dto.source,
                location_id=dto.location_id,
            )
            record.validate()
            record.effective_hours = record.calculate_effective_hours()
            saved = self.attendance_repo.save(record)

        return AttendanceResponseDTO(
            id=saved.id,
            employee_id=saved.employee_id,
            attendance_date=saved.attendance_date,
            status=saved.status,
            check_in=saved.check_in,
            check_out=saved.check_out,
            effective_hours=str(saved.effective_hours),
        )


@dataclass
class SubmitTimesheetUseCase:
    """Use Case - ارسال تایم‌شیت."""

    timesheet_repo: ITimesheetRepository
    attendance_repo: IAttendanceRecordRepository

    def execute(self, dto: SubmitTimesheetDTO, tenant_id=None):
        # Check for existing timesheet
        existing = self.timesheet_repo.find_by_employee_period(
            dto.employee_id, dto.period_start, dto.period_end
        )
        if existing and existing.status != TimesheetStatus.DRAFT:
            raise TimesheetError("تایم‌شیت برای این دوره قبلاً ارسال شده است")

        # Calculate from attendance records
        records = self.attendance_repo.find_by_employee_range(
            dto.employee_id, dto.period_start, dto.period_end
        )
        total_hours = sum(
            (r.effective_hours for r in records), Decimal("0")
        )
        working_days = len([r for r in records if r.effective_hours > 0])

        if existing:
            timesheet = existing
            timesheet.total_regular_hours = total_hours
            timesheet.total_working_days = working_days
            timesheet.notes = dto.notes
        else:
            timesheet = Timesheet(
                id=uuid4(),
                tenant_id=tenant_id,
                employee_id=dto.employee_id,
                period_start=dto.period_start,
                period_end=dto.period_end,
                total_regular_hours=total_hours,
                total_working_days=working_days,
                notes=dto.notes,
            )

        timesheet.validate()
        timesheet.submit()
        saved = self.timesheet_repo.save(timesheet)
        return saved


@dataclass
class CreateWorkScheduleUseCase:
    """Use Case - ایجاد برنامه کاری."""

    schedule_repo: IWorkScheduleRepository

    def execute(self, dto: CreateWorkScheduleDTO, tenant_id=None):
        from datetime import time as time_cls
        schedule = WorkSchedule(
            id=uuid4(),
            tenant_id=tenant_id,
            name=dto.name,
            code=dto.code,
            schedule_type=dto.schedule_type,
            break_duration_minutes=dto.break_duration_minutes,
            working_days=dto.working_days,
            daily_hours=Decimal(dto.daily_hours),
            weekly_hours=Decimal(dto.weekly_hours),
        )
        schedule.validate()
        saved = self.schedule_repo.save(schedule)
        return saved


@dataclass
class SetSalaryUseCase:
    """Use Case - تنظیم حقوق."""

    compensation_repo: ICompensationRecordRepository

    def execute(self, dto: SetSalaryDTO, tenant_id=None) -> CompensationResponseDTO:
        # End current compensation
        current = self.compensation_repo.find_current(dto.employee_id)
        if current:
            current.end(dto.effective_date, dto.reason)
            self.compensation_repo.save(current)

        # Create new compensation
        record = CompensationRecord(
            id=uuid4(),
            tenant_id=tenant_id,
            employee_id=dto.employee_id,
            pay_grade_id=dto.pay_grade_id,
            base_salary=Decimal(dto.base_salary),
            housing_allowance=Decimal(dto.housing_allowance),
            transportation_allowance=Decimal(dto.transportation_allowance),
            food_allowance=Decimal(dto.food_allowance),
            family_allowance=Decimal(dto.family_allowance),
            effective_date=dto.effective_date,
            is_current=True,
            change_reason=dto.reason,
        )
        record.validate()
        saved = self.compensation_repo.save(record)

        return CompensationResponseDTO(
            id=saved.id,
            employee_id=saved.employee_id,
            base_salary=str(saved.base_salary),
            total_monthly=str(saved.total_monthly),
            currency=saved.currency,
            effective_date=saved.effective_date,
            is_current=saved.is_current,
        )


@dataclass
class CreateBankAccountUseCase:
    """Use Case - ایجاد حساب بانکی."""

    bank_account_repo: IBankAccountRepository

    def execute(self, dto: CreateBankAccountDTO, tenant_id=None):
        # If primary, unset other primaries
        if dto.is_primary:
            existing = self.bank_account_repo.find_by_employee(dto.employee_id)
            for account in existing:
                if account.is_primary:
                    account.is_primary = False
                    self.bank_account_repo.save(account)

        account = BankAccount(
            id=uuid4(),
            tenant_id=tenant_id,
            employee_id=dto.employee_id,
            bank_name=dto.bank_name,
            branch_name=dto.branch_name,
            account_number=dto.account_number,
            sheba_number=dto.sheba_number,
            card_number=dto.card_number,
            account_holder_name=dto.account_holder_name,
            is_primary=dto.is_primary,
        )
        account.validate()
        saved = self.bank_account_repo.save(account)
        return saved
