<?php
declare(strict_types=1);

namespace CronJobs;

use App\Core\Database;
use App\Core\Logger;

/**
 * Annually (Jan 1-7): calculates carry-over from previous year and creates new year leave balances.
 * Egyptian law: max 3-year accumulation for annual leave.
 */
class HrLeaveBalanceResetJob
{
    private Database $db;
    public function __construct(Database $db) { $this->db = $db; }

    public function shouldRun(): bool
    {
        // Run in the first 7 days of January only
        return (int) date('n') === 1 && (int) date('j') <= 7;
    }

    public function run(): array
    {
        $newYear = (int) date('Y');
        $prevYear = $newYear - 1;
        $created = 0;
        $carried = 0;

        // Check if already generated for this year
        $existing = $this->db->selectOne(
            "SELECT COUNT(*) as c FROM hr_leave_balances WHERE year = ?",
            [$newYear]
        );
        if ((int) ($existing['c'] ?? 0) > 0) {
            return ['created' => 0, 'carried_over' => 0, 'skipped' => 'already_generated'];
        }

        // Get all active employees
        $employees = $this->db->select(
            "SELECT hp.id, hp.hire_date, hp.employment_type,
                    TIMESTAMPDIFF(YEAR, hp.hire_date, CURDATE()) as years_of_service,
                    TIMESTAMPDIFF(YEAR, hp.date_of_birth, CURDATE()) as age
             FROM hr_employee_profiles hp
             WHERE hp.employment_status IN ('active', 'probation')
               AND hp.is_archived = 0"
        );

        // Get all leave types
        $leaveTypes = $this->db->select(
            "SELECT * FROM hr_leave_types WHERE is_active = 1 AND is_archived = 0"
        );

        foreach ($employees as $emp) {
            $profileId = (int) $emp['id'];
            $yearsOfService = (int) ($emp['years_of_service'] ?? 0);
            $age = (int) ($emp['age'] ?? 30);

            foreach ($leaveTypes as $lt) {
                $leaveTypeId = (int) $lt['id'];

                // Calculate entitlement based on Egyptian law for annual leave
                $entitled = (float) ($lt['default_days_per_year'] ?? 0);
                if (($lt['code'] ?? '') === 'annual') {
                    if ($yearsOfService >= 10 || $age >= 50) {
                        $entitled = 30.0;
                    } elseif ($yearsOfService >= 1) {
                        $entitled = 21.0;
                    } else {
                        $entitled = 15.0; // Under 1 year
                    }
                }

                // Calculate carry-over from previous year (max per leave type config)
                $carryOver = 0.0;
                $maxCarry = (float) ($lt['max_carry_over_days'] ?? 0);
                if ($maxCarry > 0) {
                    $prevBalance = $this->db->selectOne(
                        "SELECT (entitled_days + carried_over_days + adjustment_days - used_days) as remaining_calc
                         FROM hr_leave_balances
                         WHERE employee_profile_id = ? AND leave_type_id = ? AND year = ?",
                        [$profileId, $leaveTypeId, $prevYear]
                    );
                    if ($prevBalance) {
                        $remaining = (float) ($prevBalance['remaining_calc'] ?? 0);
                        $carryOver = min($remaining, $maxCarry);
                    }
                }

                // Create new year balance
                $this->db->insert('hr_leave_balances', [
                    'employee_profile_id' => $profileId,
                    'leave_type_id'       => $leaveTypeId,
                    'year'                => $newYear,
                    'entitled_days'       => $entitled,
                    'carried_over_days'   => $carryOver,
                    'used_days'           => 0,
                    'pending_days'        => 0,
                    'adjustment_days'     => 0,
                    'created_at'          => date('Y-m-d H:i:s'),
                    'updated_at'          => date('Y-m-d H:i:s'),
                ]);
                $created++;
                if ($carryOver > 0) {
                    $carried++;
                }
            }
        }

        Logger::info("HR Leave Balance Reset: {$created} balances created for {$newYear}, {$carried} with carry-over");

        return [
            'year'         => $newYear,
            'created'      => $created,
            'carried_over' => $carried,
        ];
    }
}
