<?php

declare(strict_types=1);

namespace Kylin\Hr\Services;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Kylin\Hr\Models\SalarySlip;
use Kylin\Hr\Models\SalarySlipItem;
use Kylin\Hr\Models\SocialInsurance;
use Kylin\Hr\Models\Employee;
use Throwable;

/**
 * 薪资服务
 *
 * 处理工资条生成、社保计算等业务逻辑。
 */
class SalaryService
{
    /**
     * 计算个税（累计预扣法）
     *
     * @param float $cumulativeIncome 累计收入
     * @param float $cumulativeDeduction 累计减除费用
     * @param float $cumulativeSpecialDeduction 累计专项扣除（五险一金）
     * @param float $cumulativeAdditionalDeduction 累计专项附加扣除
     * @param float $taxPaid 已缴税额
     */
    public function calculateIncomeTax(
        float $cumulativeIncome,
        float $cumulativeDeduction,
        float $cumulativeSpecialDeduction,
        float $cumulativeAdditionalDeduction = 0,
        float $taxPaid = 0,
    ): float {
        $taxableIncome = $cumulativeIncome
            - $cumulativeDeduction
            - $cumulativeSpecialDeduction
            - $cumulativeAdditionalDeduction;

        if ($taxableIncome <= 0) {
            return 0.0;
        }

        // 税率表
        $brackets = [
            [36000, 0.03, 0],
            [144000, 0.10, 2520],
            [300000, 0.20, 16920],
            [420000, 0.25, 31920],
            [660000, 0.30, 52920],
            [960000, 0.35, 85920],
            [PHP_FLOAT_MAX, 0.45, 181920],
        ];

        $tax = 0.0;
        foreach ($brackets as [$limit, $rate, $deduction]) {
            if ($taxableIncome <= $limit) {
                $tax = $taxableIncome * $rate - $deduction;
                break;
            }
        }

        $currentTax = max($tax - $taxPaid, 0);

        return round($currentTax, 2);
    }

    /**
     * 计算员工月度薪资
     *
     * @throws Throwable
     */
    public function calculateMonthlySalary(int $employeeId, int $year, int $month): SalarySlip
    {
        return DB::transaction(function () use ($employeeId, $year, $month): SalarySlip {
            $employee = Employee::with(['socialInsurance'])->findOrFail($employeeId);

            // 应发项目
            $baseSalary = (float) $employee->base_salary;
            $positionAllowance = $baseSalary * 0.2; // 岗位津贴按基本工资20%
            $performanceBonus = $baseSalary * 0.15; // 绩效奖金按基本工资15%
            $overtimePay = 0; // 加班费从考勤计算
            $otherIncome = 0;

            $grossSalary = $baseSalary + $positionAllowance + $performanceBonus + $overtimePay + $otherIncome;

            // 五险一金（个人部分）
            $socialInsuranceDeduction = 0;
            if ($employee->socialInsurance) {
                $socialInsuranceDeduction = $employee->socialInsurance->personal_total;
            }

            // 个税（简化计算）
            $taxThreshold = config('kylin-hr.tax_threshold', 5000);
            $monthlyDeduction = $taxThreshold;
            $incomeTax = $this->calculateIncomeTax(
                $grossSalary * $month, // 累计收入
                $monthlyDeduction * $month, // 累计减除费用
                $socialInsuranceDeduction * $month, // 累计专项扣除
            );

            // 实发工资
            $totalDeduction = $socialInsuranceDeduction + $incomeTax;
            $netSalary = $grossSalary - $totalDeduction;

            // 创建工资条
            $slip = SalarySlip::updateOrCreate(
                [
                    'employee_id' => $employeeId,
                    'year' => $year,
                    'month' => $month,
                ],
                [
                    'gross_salary' => $grossSalary,
                    'total_deduction' => $totalDeduction,
                    'net_salary' => $netSalary,
                    'status' => 1,
                    'generated_at' => now(),
                ]
            );

            // 创建工资条明细
            $slip->items()->delete();
            $items = [
                ['item_name' => '基本工资', 'amount' => $baseSalary],
                ['item_name' => '岗位津贴', 'amount' => $positionAllowance],
                ['item_name' => '绩效奖金', 'amount' => $performanceBonus],
                ['item_name' => '五险一金(个人)', 'amount' => -$socialInsuranceDeduction],
                ['item_name' => '个人所得税', 'amount' => -$incomeTax],
            ];

            foreach ($items as $item) {
                $slip->items()->create($item);
            }

            Log::info('薪资核算完成', [
                'employee_id' => $employeeId,
                'year' => $year,
                'month' => $month,
                'net_salary' => $netSalary,
            ]);

            $this->audit('salary_calculated', $slip, [
                'employee_id' => $employeeId,
                'year' => $year,
                'month' => $month,
                'gross_salary' => $grossSalary,
                'net_salary' => $netSalary,
            ]);

            return $slip->fresh('items');
        });
    }

    /**
     * 记录薪资审计日志
     *
     * 依据《个人所得税法》和《劳动合同法》，
     * 薪资核算过程需记录审计日志，便于税务核查和劳动争议处理。
     */
    private function audit(string $event, SalarySlip $slip, array $extra = []): void
    {
        if (! class_exists(\Kylin\AuditLog\Models\AuditLog::class)) {
            return;
        }

        try {
            \Kylin\AuditLog\Models\AuditLog::create([
                'event' => $event,
                'model_type' => SalarySlip::class,
                'model_id' => $slip->id,
                'new_values' => $extra,
                'old_values' => null,
                'user_id' => auth()->id(),
                'ip' => request()?->ip(),
                'url' => request()?->fullUrl(),
                'tag' => 'hr-salary',
            ]);
        } catch (\Throwable $e) {
            logger()->warning('薪资审计日志写入失败', [
                'error' => $e->getMessage(),
                'employee_id' => $extra['employee_id'] ?? null,
                'event' => $event,
            ]);
        }
    }
}
