<?php

namespace App\Services;

use App\Models\User;
use App\Models\SalaryGroup;
use App\Models\CompanySetting;
use App\Models\SalaryRevision;

use Illuminate\Support\Facades\Auth;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;

class SalaryRevisionService
{
    public function createSalaryRevision(int $companyId,int $employeeId,int $salaryGroupId,int $initialAnnualCtc , $effective_date = null){
        $employee = User::find($employeeId);
        $salaryGroup = SalaryGroup::find($salaryGroupId);
        if(empty($companyId)){
            $companyId = auth()->user()->company_id;
        }

        $target = max(0, round($initialAnnualCtc, 2));
        $monthlyTarget = round($target / 12, 2);

        // Step 1: Employer deductions (PF etc.)
        $stat = $this->calculateStatutoryDeductions((int)$companyId, $monthlyTarget);

        $salaryGroupComponents = $salaryGroup?->salaryGroupComponents()?->with('salaryComponent')->get();

        $resolvedComponents = $this->buildRevisionComponentsFromCtc(
            $salaryGroupComponents instanceof EloquentCollection ? $salaryGroupComponents->toArray() : [],
            $initialAnnualCtc,
            $stat,
        );

        SalaryRevision::withoutGlobalScopes()->create([
            'company_id' => $companyId,
            'user_id' => $employee->id,
            'effective_date' => $effective_date ?? ($employee->joining_date ?? now())->toDateString(),
            'ctc_annual' => round($initialAnnualCtc, 2),
            'pf_employer' => isset($stat['pf_employer']) ? round((float) $stat['pf_employer'], 2) : null,
            'pf_employee' => isset($stat['pf']) ? round((float) $stat['pf'], 2) : null,
            'esi_employer' => isset($stat['esi_employer']) ? round((float) $stat['esi_employer'], 2) : null,
            'esi_employee' => isset($stat['esi']) ? round((float) $stat['esi'], 2) : null,
            'pt' => isset($stat['pt']) ? round((float) $stat['pt'], 2) : null,
            'components_json' => $resolvedComponents ? $this->sanitizeRevisionComponents($resolvedComponents) : null,
            'created_by' => Auth::id(),
        ]);
    }

    public function callCreateSalaryRevision(array $employeeIds, int $salaryGroupId, $companyId)
    {
        $employees = User::query()->whereIn('id', $employeeIds)->forTenantDirectory()->get();

        foreach ($employees as $employee) {
            $latestRevision = $employee->latestEffectiveSalaryRevision();

            if (!$latestRevision || $latestRevision->ctc_annual <= 0) {
                continue;
            }

            $this->createSalaryRevision(
                $companyId,
                $employee->id,
                $salaryGroupId,
                $latestRevision->ctc_annual
            );
        }
    }

    private function buildRevisionComponentsFromCtc(
        array $baseRows,
        float $targetCtcAnnual,
        array $stat
    ): array {
        $target = max(0, round($targetCtcAnnual, 2));
        $monthlyTarget = round($target / 12, 2);

        $grossMonthly = $monthlyTarget - $stat['total_employer'];
        $grossAnnual  = round($grossMonthly * 12, 2);

        $components = [];
        $basicAnnual = 0;

        // Step 3: First pass → Calculate BASIC (ctc_percent only)
        foreach ($baseRows as $row) {

            $name = $row['salary_component']['name'] ?? 'Component';
            $type = $row['salary_component']['type'] ?? 'earning';
            $valueType = $row['value_type'] ?? '';
            $value = (float) ($row['value'] ?? 0);

            if ($valueType === 'ctc_percent') {

                $annual = round(($grossAnnual * $value) / 100, 2);

                if (strtolower($name) === 'basic salary') {
                    $basicAnnual = $annual;
                }

                $components[] = [
                    'name' => $name,
                    'value_type' => $valueType,
                    'value' => $value,
                    'type' => $type,
                    'annual' => $annual,
                    'monthly' => round($annual / 12, 2),
                ];
            }
        }

        // Step 4: Second pass → Remaining components
        foreach ($baseRows as $row) {

            $name = $row['salary_component']['name'] ?? 'Component';
            $type = $row['salary_component']['type'] ?? 'earning';
            $valueType = $row['value_type'] ?? '';
            $value = (float) ($row['value'] ?? 0);

            // Skip already processed BASIC (ctc_percent)
            if ($valueType === 'ctc_percent') {
                continue;
            }

            $annual = 0;

            if ($valueType === 'basic_percent') {
                // Based on BASIC
                $annual = round(($basicAnnual * $value) / 100, 2);

            } elseif ($valueType === 'fixed' || $valueType === 'variable') {
                // Fixed monthly → annual
                $annual = $value;
            }

            $components[] = [
                'name' => $name,
                'value_type' => $valueType,
                'value' => $value,
                'type' => $type,
                'annual' => $annual,
                'monthly' => round($annual / 12, 2),
            ];
        }

        return $components;
    }

    protected function calculateStatutoryDeductions(int $companyId, float $grossAfterLop): array
    {
        $settings = $this->loadSettings((int) $companyId);
        
        $pf = 0;
        $esi = 0;
        $pfEmployer = 0;
        $esiEmployer = 0;
        $pt = 0;

        $pfEnabled = $settings['pf_enabled'];
        $esiEnabled = $settings['esi_enabled'];
        $ptEnabled = $settings['pt_enabled'];
        $pf_excluded_in_ctc = $settings['pf_excluded_in_ctc'];
        $esi_excluded_in_ctc = $settings['esi_excluded_in_ctc'];

        if ($pfEnabled) {
            $pfRate = (float) $settings['pf_rate'];
            $pfCap = (float) $settings['pf_ceiling'];
            $pfBase = min($grossAfterLop, $pfCap);
            $pf = round($pfBase * ($pfRate / 100), 2);
        }
        if ($esiEnabled) {
            $esiRate = (float) $settings['esi_employee_rate'];
            $esiEmployerRate = (float) $settings['esi_employer_rate'];
            $esiCap = (float) $settings['esi_cap'];
            if ($grossAfterLop <= $esiCap) {
                $esi = round($grossAfterLop * ($esiRate / 100), 2);
                $esiEmployer = round($grossAfterLop * ($esiEmployerRate / 100), 2);
            }
        }
        if ($ptEnabled) {
            $ptAmount = (float) $settings['pt_amount'] ?? 200;
            $pt = $ptAmount;
        }

        if (!$pf_excluded_in_ctc) {
            $pfEmployer = $pf;
        }

        if ($esi_excluded_in_ctc) {
            $esiEmployer = 0;
        }

        return [
            'pf' => $pf,
            'pf_employer' => $pfEmployer,
            'esi' => $esi,
            'esi_employer' => $esiEmployer,
            'pt' => $pt,
            'total' => round($pf + $esi + $pt, 2),
            'total_employer' => round($pfEmployer + $esiEmployer, 2),
        ];
    }
    /**
     * @param mixed $components
     * @return array<int, array{name:string, annual:float}>
     */
    private function sanitizeRevisionComponents($components): array
    {
        if (!is_array($components)) {
            return [];
        }
        $rows = [];
        foreach ($components as $component) {
            if (!is_array($component)) {
                continue;
            }
            $name = trim((string) ($component['name'] ?? ''));
            if ($name === '') {
                continue;
            }
            $annual = round(max(0, (float) ($component['annual'] ?? 0)), 2);
            $monthly = isset($component['monthly']) ? round(max(0, (float) $component['monthly']), 2) : round($annual / 12, 2);
            $rows[] = [
                'name'       => $name,
                'type'       => (string) ($component['type'] ?? 'earning'),
                'value'      => round(max(0, (float) ($component['value'] ?? 0)), 2),
                'value_type' => (string) ($component['value_type'] ?? 'fixed'),
                'annual'     => $annual,
                'monthly'    => $monthly,
            ];
        }
        return $rows;
    }

    protected function loadSettings(int $companyId): array
    {
        $keys = [
            'payroll_pf_enabled', 'payroll_pf_rate', 'payroll_pf_cap',
            'payroll_esi_enabled', 'payroll_esi_rate', 'payroll_esi_cap',
            'payroll_pt_enabled', 'payroll_pt_amount', 'pf_excluded_in_ctc' ,'esi_excluded_in_ctc'
        ];
        $rows = CompanySetting::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->whereIn('key', $keys)
            ->pluck('value', 'key');
        return [
            'pf_enabled' => ($rows['payroll_pf_enabled'] ?? '0') === '1',
            'pf_rate' => (float) ($rows['payroll_pf_rate'] ?? 12),
            'pf_ceiling' => isset($rows['payroll_pf_cap']) ? (float) $rows['payroll_pf_cap'] : 15000,
            'esi_enabled' => ($rows['payroll_esi_enabled'] ?? '0') === '1',
            'esi_employee_rate' => (float) ($rows['payroll_esi_rate'] ?? 0.75),
            'esi_employer_rate' => 3.25,
            'esi_cap' => isset($rows['payroll_esi_cap']) ? (float) $rows['payroll_esi_cap'] : 21000,
            'pt_enabled' => ($rows['payroll_pt_enabled'] ?? '0') === '1',
            'pt_amount' => isset($rows['payroll_pt_amount']) ? (float) $rows['payroll_pt_amount'] : 200,
            'pf_excluded_in_ctc' => ($rows['pf_excluded_in_ctc'] ?? '0') === '1',
            'esi_excluded_in_ctc' => ($rows['esi_excluded_in_ctc'] ?? '0') === '1',
        ];
    }
}