<?php
declare(strict_types=1);

namespace App\Modules\HR\Services;

use App\Core\App;
use App\Core\Logger;
use App\Modules\HR\Models\HrDisciplinaryAction;

/**
 * Disciplinary Action Service
 *
 * Egyptian Labour Law Art. 58-68:
 *   - Investigation required before any penalty
 *   - Max wage deduction: 5 days/month
 *   - Max suspension: 6 days/month
 *   - Employee has 7-day appeal window
 *   - Progressive discipline: warning -> deduction -> suspension -> demotion -> termination
 */
final class DisciplinaryService
{
    /**
     * Validate penalty against Art.58 monthly limits.
     */
    public static function validatePenalty(int $profileId, string $penaltyType, int $days, string $enforcementDate): array
    {
        $year = (int) date('Y', strtotime($enforcementDate));
        $month = (int) date('m', strtotime($enforcementDate));

        $errors = [];

        if ($penaltyType === 'deduction') {
            $currentTotal = HrDisciplinaryAction::getMonthlyDeductionDays($profileId, $year, $month);
            $maxAllowed = self::getMaxDeductionDays();
            $remaining = $maxAllowed - $currentTotal;
            if ($days > $remaining) {
                $errors[] = "تجاوز الحد الأقصى لخصم الراتب الشهري ({$maxAllowed} أيام). المتبقي: {$remaining} أيام (مادة 58)";
            }
        }

        if ($penaltyType === 'suspension') {
            $currentTotal = HrDisciplinaryAction::getMonthlySuspensionDays($profileId, $year, $month);
            $maxAllowed = self::getMaxSuspensionDays();
            $remaining = $maxAllowed - $currentTotal;
            if ($days > $remaining) {
                $errors[] = "تجاوز الحد الأقصى للإيقاف الشهري ({$maxAllowed} أيام). المتبقي: {$remaining} أيام";
            }
        }

        return $errors;
    }

    /**
     * Check if appeal is still within the 7-day window.
     */
    public static function canAppeal(array $action): bool
    {
        if ($action['status'] !== 'enforced') {
            return false;
        }
        $enforcementDate = $action['enforcement_date'] ?? null;
        if (!$enforcementDate) {
            return false;
        }
        $appealDeadline = date('Y-m-d', strtotime($enforcementDate . ' +' . self::getAppealWindowDays() . ' days'));
        return date('Y-m-d') <= $appealDeadline;
    }

    /**
     * Calculate wage deduction amount for payroll.
     */
    public static function getMonthlyDeductionAmount(int $profileId, string $basicSalary, int $year, int $month): string
    {
        $deductionDays = HrDisciplinaryAction::getMonthlyDeductionDays($profileId, $year, $month);
        if ($deductionDays <= 0) {
            return '0.00';
        }
        $dailyRate = bcdiv($basicSalary, '30', 4);
        return bcmul($dailyRate, (string) $deductionDays, 2);
    }

    private static function getMaxDeductionDays(): int
    {
        $db = App::getInstance()->db();
        $row = $db->selectOne("SELECT config_value FROM system_config WHERE config_key = 'hr.discipline.max_wage_deduction_days_per_month'");
        return (int) ($row['config_value'] ?? 5);
    }

    private static function getMaxSuspensionDays(): int
    {
        $db = App::getInstance()->db();
        $row = $db->selectOne("SELECT config_value FROM system_config WHERE config_key = 'hr.discipline.max_suspension_days_per_month'");
        return (int) ($row['config_value'] ?? 6);
    }

    private static function getAppealWindowDays(): int
    {
        $db = App::getInstance()->db();
        $row = $db->selectOne("SELECT config_value FROM system_config WHERE config_key = 'hr.discipline.appeal_window_days'");
        return (int) ($row['config_value'] ?? 7);
    }
}
