<?php
declare(strict_types=1);

namespace App\Modules\HR\Services;

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

/**
 * Social Insurance Calculation Service
 *
 * Egyptian Social Insurance Law 148/2019:
 *   Employee share: 9% basic + 2% variable = 11%
 *   Employer share: 12% basic + 6.75% variable = 18.75%
 *   Subject to ceiling caps (updated annually by admin in system_config)
 *
 * All arithmetic uses bcmath with scale=2.
 */
final class SocialInsuranceService
{
    public static function calculate(string $basicSalary, string $variableSalary): array
    {
        $config = self::loadConfig();

        // Apply ceilings
        $basicInsurable = self::applyCeiling(
            self::applyFloor($basicSalary, $config['basic_floor']),
            $config['basic_ceiling']
        );
        $variableInsurable = self::applyCeiling(
            self::applyFloor($variableSalary, $config['variable_floor']),
            $config['variable_ceiling']
        );

        // Employee shares
        $employeeBasic    = bcmul($basicInsurable, bcdiv($config['employee_basic_pct'], '100', 6), 2);
        $employeeVariable = bcmul($variableInsurable, bcdiv($config['employee_variable_pct'], '100', 6), 2);
        $totalEmployee    = bcadd($employeeBasic, $employeeVariable, 2);

        // Employer shares
        $employerBasic    = bcmul($basicInsurable, bcdiv($config['employer_basic_pct'], '100', 6), 2);
        $employerVariable = bcmul($variableInsurable, bcdiv($config['employer_variable_pct'], '100', 6), 2);
        $totalEmployer    = bcadd($employerBasic, $employerVariable, 2);

        $totalContribution = bcadd($totalEmployee, $totalEmployer, 2);

        return [
            'basic_insurable_salary'    => $basicInsurable,
            'variable_insurable_salary' => $variableInsurable,
            'employee_basic_share'      => $employeeBasic,
            'employee_variable_share'   => $employeeVariable,
            'total_employee_share'      => $totalEmployee,
            'employer_basic_share'      => $employerBasic,
            'employer_variable_share'   => $employerVariable,
            'total_employer_share'      => $totalEmployer,
            'total_contribution'        => $totalContribution,
            'rates' => [
                'employee_basic_pct'    => $config['employee_basic_pct'],
                'employee_variable_pct' => $config['employee_variable_pct'],
                'employer_basic_pct'    => $config['employer_basic_pct'],
                'employer_variable_pct' => $config['employer_variable_pct'],
                'basic_ceiling'         => $config['basic_ceiling'],
                'variable_ceiling'      => $config['variable_ceiling'],
            ],
        ];
    }

    private static function applyCeiling(string $amount, string $ceiling): string
    {
        if (bccomp($ceiling, '0', 2) <= 0) {
            return $amount;
        }
        return bccomp($amount, $ceiling, 2) > 0 ? $ceiling : $amount;
    }

    private static function applyFloor(string $amount, string $floor): string
    {
        if (bccomp($floor, '0', 2) <= 0) {
            return $amount;
        }
        return bccomp($amount, $floor, 2) < 0 ? $floor : $amount;
    }

    private static function loadConfig(): array
    {
        $db = App::getInstance()->db();

        // Try the dedicated hr_insurance_config table first (2024+ rates with effective dates)
        $record = $db->selectOne(
            "SELECT * FROM hr_insurance_config WHERE is_active = 1 ORDER BY effective_date DESC LIMIT 1"
        );

        if ($record) {
            return [
                'employee_basic_pct'    => bcmul((string) $record['employee_basic_rate'], '100', 2),
                'employee_variable_pct' => bcmul((string) $record['employee_variable_rate'], '100', 2),
                'employer_basic_pct'    => bcmul((string) $record['employer_basic_rate'], '100', 2),
                'employer_variable_pct' => bcmul((string) $record['employer_variable_rate'], '100', 2),
                'basic_ceiling'         => (string) $record['basic_salary_cap'],
                'variable_ceiling'      => (string) $record['variable_salary_cap'],
                'basic_floor'           => (string) ($record['min_subscription_salary'] ?? '2000.00'),
                'variable_floor'        => '0.00',
            ];
        }

        // Fallback to system_config
        $rows = $db->select(
            "SELECT config_key, config_value FROM system_config WHERE config_key LIKE 'hr.insurance.%'"
        );

        $cfg = [];
        foreach ($rows as $row) {
            $key = str_replace('hr.insurance.', '', $row['config_key']);
            $cfg[$key] = $row['config_value'];
        }

        return [
            'employee_basic_pct'    => $cfg['employee_basic_pct'] ?? '11.00',
            'employee_variable_pct' => $cfg['employee_variable_pct'] ?? '11.00',
            'employer_basic_pct'    => $cfg['employer_basic_pct'] ?? '18.75',
            'employer_variable_pct' => $cfg['employer_variable_pct'] ?? '15.75',
            'basic_ceiling'         => $cfg['basic_salary_ceiling'] ?? '12600.00',
            'variable_ceiling'      => $cfg['variable_salary_ceiling'] ?? '10080.00',
            'basic_floor'           => $cfg['basic_salary_floor'] ?? '2000.00',
            'variable_floor'        => $cfg['variable_salary_floor'] ?? '0.00',
        ];
    }
}
