<?php

namespace App\Services\Payroll;

use App\Models\IncomeTaxPlan;
use App\Models\TaxSlab;
use Illuminate\Support\Collection;

class TdsCalculator
{
    /**
     * @return array{taxable_income: float, annual_tax: float, cess_amount: float}
     */
    public function compute(IncomeTaxPlan $plan, float $grossAnnual, float $deductionsTotal): array
    {
        $standard = (float) ($plan->standard_deduction ?? 0);
        $deductions = $plan->allow_deductions ? min($deductionsTotal, $this->maxDeductionCap()) : 0;

        $taxable = max(0, $grossAnnual - $standard - $deductions);
        $slabs = $plan->taxSlabs()->orderBy('slab_no')->get();

        if ($slabs->isEmpty()) {
            return [
                'taxable_income' => round($taxable, 2),
                'annual_tax' => 0.0,
                'cess_amount' => 0.0,
            ];
        }

        $baseTax = $this->slabTax($taxable, $slabs);
        $cessRate = (float) ($slabs->last()->cess_rate ?? 4);
        $cess = round($baseTax * ($cessRate / 100), 2);
        $annualTax = round($baseTax + $cess, 2);

        return [
            'taxable_income' => round($taxable, 2),
            'annual_tax' => $annualTax,
            'cess_amount' => $cess,
        ];
    }

    protected function maxDeductionCap(): float
    {
        return 500000.0;
    }

    protected function slabTax(float $income, Collection $slabs): float
    {
        if ($income <= 0) {
            return 0.0;
        }

        $tax = 0.0;

        foreach ($slabs as $slab) {
            /** @var TaxSlab $slab */
            $min = (float) $slab->min_amount;
            $max = $slab->max_amount !== null ? (float) $slab->max_amount : null;

            if ($income <= $min) {
                break;
            }

            $upper = $max ?? $income;
            $taxableInSlab = min($income, $upper) - $min;

            if ($taxableInSlab > 0) {
                $tax += $taxableInSlab * ((float) $slab->tax_rate / 100);
            }
        }

        return round($tax, 2);
    }
}
