<?php

namespace App\Modules\Payroll\Services;

use App\Modules\HR\Attendance\Repositories\AttendanceRecordRepository;
use App\Modules\HR\Employees\Models\Employee;
use App\Modules\HR\Leave\Services\LeavePayrollDaysService;
use App\Modules\HR\Overtime\Repositories\OvertimeRequestRepository;
use App\Modules\Payroll\Repositories\PayrollAdjustmentRepository;

class PayrollInputAggregationService
{
    public function __construct(
        private readonly AttendanceRecordRepository $attendance,
        private readonly LeavePayrollDaysService $leaveDays,
        private readonly OvertimeRequestRepository $overtime,
        private readonly PayrollAdjustmentRepository $adjustments,
        private readonly PayrollLeaveDeductionCalculator $leaveDeduction,
    ) {}

    /**
     * @return array{
     *   base_salary: string,
     *   attendance_days: int,
     *   absent_days: int,
     *   late_days: int,
     *   leave_days: float,
     *   overtime_minutes: int,
     *   adjustments_total: string,
     *   snapshot_data: array<string, mixed>,
     *   gross_amount: string
     * }
     */
    public function aggregateForEmployee(
        int $tenantId,
        int $employeeId,
        string $periodStart,
        string $periodEnd,
        int $payrollPeriodId,
    ): array {
        $emp = Employee::query()
            ->where('tenant_id', $tenantId)
            ->whereKey($employeeId)
            ->first(['id', 'salary']);
        $base = $emp !== null ? (string) $emp->salary : '0.00';
        $counts = $this->attendance->payrollStatusCountsForEmployeeInRange(
            $tenantId,
            $employeeId,
            $periodStart,
            $periodEnd,
        );
        $attendanceDays = $counts['present'] + $counts['late'] + $counts['half_day'] + $counts['holiday'];
        $leaveDays = $this->leaveDays->sumApprovedDaysInRange(
            $tenantId,
            $employeeId,
            $periodStart,
            $periodEnd,
        );
        $unpaidLeaveDays = $this->leaveDays->sumApprovedDaysInRange(
            $tenantId,
            $employeeId,
            $periodStart,
            $periodEnd,
            false,
        );
        $leaveDeductionAmount = $this->leaveDeduction->amountFromDays((float) $base, $unpaidLeaveDays);
        $adj = $this->adjustments->sumSignedForEmployeePeriod($tenantId, $employeeId, $payrollPeriodId);
        $gross = (string) round((float) $base + (float) $adj - (float) $leaveDeductionAmount, 2);
        $approvedOt = $this->overtime->approvedOvertimeMinutesForEmployeeInRange(
            $tenantId,
            $employeeId,
            $periodStart,
            $periodEnd,
        );

        return [
            'base_salary' => $base,
            'attendance_days' => $attendanceDays,
            'absent_days' => $counts['absent'],
            'late_days' => $counts['late'],
            'leave_days' => $leaveDays,
            'overtime_minutes' => $approvedOt ?? $counts['overtime_minutes'],
            'adjustments_total' => $adj,
            'snapshot_data' => [
                'attendance_status_breakdown' => $counts,
                'period_start' => $periodStart,
                'period_end' => $periodEnd,
                'overtime_source' => $approvedOt !== null ? 'approved_requests' : 'attendance_records',
                'unpaid_leave_days' => $unpaidLeaveDays,
                'leave_deduction_amount' => $leaveDeductionAmount,
            ],
            'gross_amount' => $gross,
        ];
    }
}
