<?php
declare(strict_types=1);

namespace App\Modules\HR\Services;

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

/**
 * Egyptian Income Tax Calculation Service
 *
 * 2024-2025 Progressive Tax Brackets (annual):
 *   0 - 40,000:       0%
 *   40,001 - 55,000:  10%
 *   55,001 - 70,000:  15%
 *   70,001 - 200,000: 20%
 *   200,001 - 400,000: 22.5%
 *   400,001 - 1,200,000: 25%
 *   Above 1,200,000:  27.5%
 *
 * Personal exemption: 20,000 EGP/year
 * Insurance exemption: employee's social insurance contribution
 *
 * YTD tracking ensures accurate monthly withholding:
 *   monthly_tax = (annual_tax / 12 * current_month) - ytd_tax_already_paid
 *
 * All arithmetic uses bcmath with scale=2.
 */
final class IncomeTaxService
{
    /**
     * Calculate monthly tax for an employee.
     *
     * @param string $grossTaxableMonthly  Total taxable monthly income
     * @param string $monthlyInsurance     Employee's monthly insurance contribution (exempt)
     * @param string $ytdTaxableIncome     Year-to-date taxable income before this month
     * @param string $ytdTaxPaid           Year-to-date tax already paid
     * @param int    $currentMonth         Current month number (1-12)
     */
    public static function calculateMonthly(
        string $grossTaxableMonthly,
        string $monthlyInsurance,
        string $ytdTaxableIncome,
        string $ytdTaxPaid,
        int $currentMonth
    ): array {
        $config = self::loadConfig();
        $personalExemption = $config['personal_exemption'];
        $brackets = $config['brackets'];

        // Annual projection: (gross - insurance) * 12
        $monthlyNet = bcsub($grossTaxableMonthly, $monthlyInsurance, 2);
        $annualTaxableIncome = bcmul($monthlyNet, '12', 2);

        // Subtract personal exemption
        $annualAfterExemption = bcsub($annualTaxableIncome, $personalExemption, 2);
        if (bccomp($annualAfterExemption, '0', 2) < 0) {
            $annualAfterExemption = '0.00';
        }

        // Calculate annual tax using progressive brackets
        $annualTax = self::applyBrackets($annualAfterExemption, $brackets);

        // YTD method: what should have been paid through this month
        // accumulated_tax = annual_tax / 12 * current_month
        $accumulatedTax = bcdiv(bcmul($annualTax, (string) $currentMonth, 4), '12', 2);

        // Monthly tax = accumulated - already paid
        $monthlyTax = bcsub($accumulatedTax, $ytdTaxPaid, 2);
        if (bccomp($monthlyTax, '0', 2) < 0) {
            $monthlyTax = '0.00';
        }

        // New YTD totals
        $newYtdTaxableIncome = bcadd($ytdTaxableIncome, $monthlyNet, 2);
        $newYtdTax = bcadd($ytdTaxPaid, $monthlyTax, 2);

        // Insurance exemption (annual)
        $annualInsurance = bcmul($monthlyInsurance, '12', 2);

        return [
            'gross_taxable_monthly'  => $grossTaxableMonthly,
            'annual_taxable_income'  => $annualTaxableIncome,
            'personal_exemption'     => $personalExemption,
            'insurance_exemption'    => $annualInsurance,
            'net_taxable_income'     => $annualAfterExemption,
            'annual_tax'             => $annualTax,
            'monthly_tax'            => $monthlyTax,
            'ytd_tax'                => $newYtdTax,
            'ytd_taxable_income'     => $newYtdTaxableIncome,
            'calculation_json' => [
                'brackets_applied' => self::getBracketBreakdown($annualAfterExemption, $brackets),
                'personal_exemption' => $personalExemption,
                'insurance_exemption' => $annualInsurance,
                'method' => 'ytd_cumulative',
                'month' => $currentMonth,
            ],
        ];
    }

    private static function applyBrackets(string $taxableIncome, array $brackets): string
    {
        $totalTax = '0.00';

        foreach ($brackets as $bracket) {
            $from = (string) $bracket['from'];
            $to = (string) $bracket['to'];
            $rate = (string) $bracket['rate'];

            if (bccomp($taxableIncome, $from, 2) <= 0) {
                break;
            }

            if ($to === '0' || bccomp($to, '0', 2) === 0) {
                // Last bracket (no upper limit)
                $taxable = bcsub($taxableIncome, $from, 2);
            } else {
                $upper = bccomp($taxableIncome, $to, 2) > 0 ? $to : $taxableIncome;
                $taxable = bcsub($upper, $from, 2);
            }

            if (bccomp($taxable, '0', 2) > 0 && bccomp($rate, '0', 2) > 0) {
                $bracketTax = bcmul($taxable, bcdiv($rate, '100', 6), 2);
                $totalTax = bcadd($totalTax, $bracketTax, 2);
            }
        }

        return $totalTax;
    }

    private static function getBracketBreakdown(string $taxableIncome, array $brackets): array
    {
        $breakdown = [];

        foreach ($brackets as $bracket) {
            $from = (string) $bracket['from'];
            $to = (string) $bracket['to'];
            $rate = (string) $bracket['rate'];

            if (bccomp($taxableIncome, $from, 2) <= 0) {
                break;
            }

            if ($to === '0' || bccomp($to, '0', 2) === 0) {
                $taxable = bcsub($taxableIncome, $from, 2);
            } else {
                $upper = bccomp($taxableIncome, $to, 2) > 0 ? $to : $taxableIncome;
                $taxable = bcsub($upper, $from, 2);
            }

            $tax = '0.00';
            if (bccomp($taxable, '0', 2) > 0 && bccomp($rate, '0', 2) > 0) {
                $tax = bcmul($taxable, bcdiv($rate, '100', 6), 2);
            }

            $breakdown[] = [
                'from'    => $from,
                'to'      => $to,
                'rate'    => $rate,
                'taxable' => $taxable,
                'tax'     => $tax,
            ];
        }

        return $breakdown;
    }

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

        // Try dedicated hr_tax_brackets table first
        $dbBrackets = $db->select(
            "SELECT from_amount, to_amount, rate, annual_exemption
             FROM hr_tax_brackets
             WHERE is_active = 1
             ORDER BY bracket_order ASC"
        );

        if (!empty($dbBrackets)) {
            $personalExemption = '0.00';
            $brackets = [];
            foreach ($dbBrackets as $b) {
                if (bccomp((string) $b['annual_exemption'], '0', 2) > 0) {
                    $personalExemption = (string) $b['annual_exemption'];
                }
                $brackets[] = [
                    'from' => (string) $b['from_amount'],
                    'to'   => (string) $b['to_amount'],
                    'rate' => bcmul((string) $b['rate'], '100', 2),
                ];
            }
            if (bccomp($personalExemption, '0', 2) <= 0) {
                $personalExemption = '20000.00';
            }
            return ['personal_exemption' => $personalExemption, 'brackets' => $brackets];
        }

        // Fallback to system_config
        $exemptionRow = $db->selectOne(
            "SELECT config_value FROM system_config WHERE config_key = 'hr.tax.personal_exemption'"
        );
        $personalExemption = $exemptionRow['config_value'] ?? '20000.00';

        $bracketsRow = $db->selectOne(
            "SELECT config_value FROM system_config WHERE config_key = 'hr.tax.brackets_json'"
        );
        $brackets = json_decode($bracketsRow['config_value'] ?? '[]', true) ?: [
            ['from' =>       0, 'to' =>   40000, 'rate' =>  0.00],
            ['from' =>   40000, 'to' =>   55000, 'rate' => 10.00],
            ['from' =>   55000, 'to' =>   70000, 'rate' => 15.00],
            ['from' =>   70000, 'to' =>  200000, 'rate' => 20.00],
            ['from' =>  200000, 'to' =>  400000, 'rate' => 22.50],
            ['from' =>  400000, 'to' => 1200000, 'rate' => 25.00],
            ['from' => 1200000, 'to' =>       0, 'rate' => 27.50],
        ];

        return [
            'personal_exemption' => $personalExemption,
            'brackets'           => $brackets,
        ];
    }
}
