<?php

namespace App\Services;

use App\Employee;
use App\Helpers\Severance;
use App\PositionHistory;
use Carbon\Carbon;

class EmployeeService
{
	private $_startDate;
	private $_endDate;
	private $_positionName = "執行役員(雇用)";
	
	public function calculateSeverancePayment(Employee $employee, $payouts, $pointTable, $fiscalYear = null)
	{
		// Khai báo thông tin cố định
		$pointRateValue = (float)config('settings.point_rate');
		if (!$pointRateValue || $pointRateValue == 0) $pointRateValue = 10000;
		$workingYears = 0;
		$workingMonths = 0;
		$tenureMonths = 0;
		$totalTenureYears = 0;
		$totalPoints = 0;
		$totalAmount = 0;
		$paymentPercent = 0;
		$finalAmount = 0;
		$retirementFundAmount = 0;
		$severanceAmount = 0;
		$totalLeaveMonths = 0;
		$totalLeaveYears = 0;
		$totalMonthsAffect = 0;
		$totalYearsAffect = 0;
		$leaveItems = [];
		$tenurePoints = 0;
		$tenureItems = [];
		$levelPoints = 0;
		$levelItems = [];
		$positionPoints = 0;
		$positionItems = [];
		$tenureTransitionPoints = 0;
		$levelTransitionPoints = 0;
		$positionTransitionPoints = 0;
		$totalPointOfTenure = 0;
		$totalPointOfLevel = 0;
		$totalPointOfPosition = 0;
		
		// Xử lý chức vụ đặc biệt
		$positionChangeDate = null;
		foreach ($employee->positionHistories as $item) {
			if ($item->position->name == $this->_positionName) {
				$positionChangeDate = Carbon::parse($item->from_date);
			}
		}
		if (!$positionChangeDate) {
			if ($employee->position->name == $this->_positionName) {
				$positionHistory = PositionHistory::select('to_date')->where('employee_id', $employee->id)->orderBy('to_date', 'desc')->first();
				if ($positionHistory) {
					$positionChangeDate = Carbon::parse($positionHistory->to_date)->addDay();
				} else {
					$positionChangeDate = Carbon::parse($employee->updated_at);
				}
			}
		}
		
		$calculateDates = Severance::calculateTime($employee->date_of_birth, $employee->join_date, $employee->resigned_date, $positionChangeDate, $fiscalYear);
		if ($calculateDates) {
			$this->_startDate = Carbon::parse($calculateDates['start_date'])->startOfMonth();
			$this->_endDate = Carbon::parse($calculateDates['end_date']);

			// Working Years (decimal) and Working Months (integer)
			$workingYears = $this->calculateWorkingYears($this->_startDate, $this->_endDate);
			$workingMonths = $this->calculateWorkingMonths($this->_startDate, $this->_endDate);
			
			// Lấy về điểm chuyển tiếp
			$tenureTransitionPoints = $employee->transitionPoint->tenure_points ?? 0;
			$levelTransitionPoints = $employee->transitionPoint->level_points ?? 0;
			$positionTransitionPoints = $employee->transitionPoint->position_points ?? 0;
			
			// Thiết lập điểm tổng
			$totalPointOfTenure = $tenureTransitionPoints;
			$totalPointOfLevel = $levelTransitionPoints;
			$totalPointOfPosition = $positionTransitionPoints;
			
			// ============================ Leave history ============================
			foreach ($employee->leaveHistories as $item) {
				$leaveStartDate = $item->from_date ? Carbon::parse($item->from_date) : null;
				$leaveEndDate = $item->to_date ? Carbon::parse($item->to_date) : null;
				if (!$leaveStartDate || !$leaveEndDate) continue;
				
				$checkOverlap = $this->checkTimeRangeOverlap($leaveStartDate, $leaveEndDate, $this->_startDate, $this->_endDate);
				if (!$checkOverlap) continue;
				
				$startTime = $checkOverlap['start'];
				$endTime = $checkOverlap['end'];
				$leaveMonths = $this->calculateMonthsBetween($startTime->format('Y-m-d'), $endTime->format('Y-m-d'));
				$leaveMonthAffect = 0;
				if ($item->leaveType && $item->leaveType->tenure_calculation_rate < 100) {
					$leaveMonthAffect = $leaveMonths * (100 - $item->leaveType->tenure_calculation_rate) / 100;
					$leaveMonthAffect = floor($leaveMonthAffect);
				}
				$leaveItems[] = [
					'from_date'         => $startTime->format('Y/m/d'),
					'to_date'           => $endTime->format('Y/m/d'),
					'name'              => $item->leaveType ? $item->leaveType->name : null,
					'affect_tenure'     => true, //$item->leaveType ? $item->leaveType->affect_tenure : 0,
					'percent'           => $item->leaveType ? $item->leaveType->tenure_calculation_rate : 0,
					'total_leave_month' => $leaveMonths,
					'total_leave_year'  => $this->convertMonthsToYear($leaveMonths),
					'affect_month'      => $leaveMonthAffect,
					'affect_year'       => $this->convertMonthsToYear($leaveMonthAffect)
				];
				$totalLeaveMonths += $leaveMonths;
				$totalLeaveYears += $leaveMonths;
				$totalMonthsAffect += $leaveMonthAffect;
			}
			
			$totalLeaveYears = $this->convertMonthsToYear($totalLeaveYears);
			$totalYearsAffect = $this->convertMonthsToYear($totalMonthsAffect);
			$leaveItems = $this->sortTimeRanges($leaveItems);
			
			// ============================ Level history ============================
			$listLevelHistories = $this->getLevelHistoriesByFiscalYear($employee);
			foreach ($listLevelHistories as $item) {
				$levelItems[] = $item;
				$levelPoints += $item['point'];
				$totalPointOfLevel += $item['point'];
			}
			
			// ============================ Position history ============================
			$listPositionHistories = $this->getPositionHistoriesByFiscalYear($employee);
			foreach ($listPositionHistories as $item) {
				$positionItems[] = $item;
				$positionPoints += $item['point'];
				$totalPointOfPosition += $item['point'];
			}
			
			// Tenure point - Calculate using months to avoid rounding errors
			// Example: 10年0ヶ月 - 0年9ヶ月 = 9年3ヶ月 (not 10.0 - 0.8 = 9.2)
			$tenureMonths = $workingMonths - $totalMonthsAffect;
			$tenureMonths = max(0, $tenureMonths);
			// Convert to decimal years for point calculation
			$totalTenureYears = round($tenureMonths / 12, 1);
			$tenurePoints = $this->calculateTenurePoints($totalTenureYears, $pointTable);
			$tenureItems = $this->calculateTenurePointsDetail($totalTenureYears, $pointTable);
			$totalPointOfTenure += $tenurePoints;
			
			// Payment percent
			$paymentPercent = $this->calculateRateFromYears($totalTenureYears, $payouts);
			
			// Total
			$retirementFundAmount = '0.00';
			if ($employee->retirementFund) $retirementFundAmount = number_format($employee->retirementFund->amount, 2, '.', '');
			$totalPoints = ($totalPointOfTenure + $totalPointOfLevel + $totalPointOfPosition);
			$totalPoints = ($totalPoints >= 0) ? $totalPoints : 0;
			// Round to 2 decimal places (round half up)
			$totalPoints = round($totalPoints, 2);
			$totalAmount = ($totalPoints * $pointRateValue);
			$finalAmount = ($totalAmount * $paymentPercent / 100);
			$severanceAmount = bcsub(number_format($finalAmount, 2, '.', ''), $retirementFundAmount, 2);
		}
		
		return [
			'id'                     => $employee->id,
			'code'                   => $employee->employee_code,
			'first_name'             => $employee->first_name,
			'last_name'              => $employee->last_name,
			'first_name_kana'        => $employee->first_name_kana,
			'last_name_kana'         => $employee->last_name_kana,
			'full_name'              => $employee->full_name,
			'full_name_kana'         => $employee->full_name_kana,
			'date_of_birth'          => $employee->date_of_birth ? Carbon::parse($employee->date_of_birth)->format('Y/m/d') : '',
			'join_date'              => $employee->join_date ? Carbon::parse($employee->join_date)->format('Y/m/d') : '',
			'department_id'          => $employee->department ? $employee->department->id : '',
			'department_code'        => $employee->department ? $employee->department->code : '',
			'department_name'        => $employee->department ? $employee->department->name : '',
			'position_id'            => $employee->position ? $employee->position->id : '',
			'position_code'          => $employee->position ? $employee->position->code : '',
			'position_name'          => $employee->position ? $employee->position->name : '',
			'position_point_value'   => $employee->position ? $employee->position->point_value : '',
			'level_id'               => $employee->level ? $employee->level->id : '',
			'level_code'             => $employee->level ? $employee->level->code : '',
			'level_name'             => $employee->level ? $employee->level->name : '',
			'level_point_value'      => $employee->level ? $employee->level->points : '',
			'salary_grade'           => $employee->salary_grade,
			'employment_status'      => $employee->employment_status,
			'resigned_date'          => $employee->resigned_date ? Carbon::parse($employee->resigned_date)->format('Y/m/d') : '',
			'resigned_reason'        => $employee->resigned_reason,
			'fiscal_year'            => $this->_endDate ? $this->_endDate->year : Carbon::now()->year,
			'fiscal_date'            => $this->_endDate ? $this->_endDate->format('Y-m-d') : Carbon::create(Carbon::now()->year, 3, 31)->format('Y-m-d'),
			'calculate_fiscal_year'  => $this->_endDate ? $this->_endDate->year : Carbon::now()->year,
			'calculate_fiscal_date'  => $this->_endDate ? $this->_endDate->format('Y-m-d') : Carbon::create(Carbon::now()->year, 3, 31)->format('Y-m-d'),
			'total_working_year'         => $workingYears,
			'total_working_year_display' => $this->formatYearsMonths($workingMonths),
			'total_working_months'       => $workingMonths,
			'point_rate'                 => $pointRateValue,
			'tenure_year'                => $totalTenureYears,
			'tenure_year_display'        => $this->formatYearsMonths($tenureMonths),
			'tenure_months'              => $tenureMonths,
			'tenure_point'           => $totalPointOfTenure,
			'tenure_amount'          => ($totalPointOfTenure * $pointRateValue),
			'level_point'            => $totalPointOfLevel,
			'level_amount'           => ($totalPointOfLevel * $pointRateValue),
			'position_point'         => $totalPointOfPosition,
			'position_amount'        => ($totalPointOfPosition * $pointRateValue),
			'total_point'            => $totalPoints,
			'total_amount'           => $totalAmount,
			'payment_percent'        => $paymentPercent,
			'final_amount'           => $finalAmount,
			'retirement_fund_amount' => $retirementFundAmount,
			'severance_amount'       => $severanceAmount,
			'leave'                  => [
				'total_leave_months'   => $totalLeaveMonths,
				'total_leave_years'    => $totalLeaveYears,
				'total_leave_display'  => $this->formatYearsMonths($totalLeaveMonths),
				'total_affect_months'  => $totalMonthsAffect,
				'total_affect_years'   => $totalYearsAffect,
				'total_affect_display' => $this->formatYearsMonths($totalMonthsAffect),
				'details'              => $leaveItems,
			],
			'tenure'                 => [
				'transition_points' => $tenureTransitionPoints,
				'points'            => $tenurePoints,
				'total_points'      => $totalPointOfTenure,
				'details'           => $tenureItems,
			],
			'level'                  => [
				'transition_points' => $levelTransitionPoints,
				'points'            => $levelPoints,
				'total_points'      => $totalPointOfLevel,
				'details'           => $levelItems,
			],
			'position'               => [
				'transition_points' => $positionTransitionPoints,
				'points'            => $positionPoints,
				'total_points'      => $totalPointOfPosition,
				'details'           => $positionItems,
			],
		];
	}
	
	/**
	 * Tính số tháng giữa 2 ngày theo quy tắc Nhật Bản
	 *
	 * Xử lý các trường hợp đặc biệt:
	 * 1. Full fiscal year: 04/01/Y → 03/31/(Y+N) = N × 12 tháng
	 * 2. Full short month: 02/01 → 02/28(29) = 1 tháng (dù Feb chỉ có 28/29 ngày)
	 * 3. Standard: Sử dụng diffInMonths + kiểm tra phần dư
	 *
	 * @param mixed $fromDate
	 * @param mixed $toDate
	 * @return int Số tháng (làm tròn xuống)
	 */
	private function calculateMonthsBetween($fromDate, $toDate)
	{
		if ($fromDate === null || $toDate === null) return 0;
		$startDate = ($fromDate instanceof Carbon ? $fromDate->copy() : Carbon::parse($fromDate))->startOfDay();
		$endDate = ($toDate instanceof Carbon ? $toDate->copy() : Carbon::parse($toDate))->startOfDay();

		if ($endDate->lt($startDate)) return 0;

		// ========================================
		// Pattern 1: Full fiscal year(s) detection
		// 会計年度の完全な年を検出
		// D/M/Y → (D-1)/M/(Y+N) = N × 12 tháng
		// Ví dụ: 04/01/2015 → 03/31/2016 = 12 tháng
		// Ví dụ: 04/01/2014 → 03/31/2016 = 24 tháng
		// ========================================
		$endPlusOneDay = $endDate->copy()->addDay();
		if ($endPlusOneDay->day === $startDate->day
			&& $endPlusOneDay->month === $startDate->month
			&& $endPlusOneDay->year > $startDate->year) {
			return ($endPlusOneDay->year - $startDate->year) * 12;
		}

		// ========================================
		// Pattern 2: Full month within same month
		// 同月内の完全な月を検出 (短い月対応)
		// 1st → last day of same month = 1 tháng
		// Ví dụ: 02/01 → 02/28 (năm thường) = 1 tháng
		// Ví dụ: 02/01 → 02/29 (năm nhuận) = 1 tháng
		// ========================================
		if ($startDate->day === 1
			&& $endDate->day === $endDate->daysInMonth
			&& $startDate->isSameMonth($endDate)) {
			return 1;
		}

		// ========================================
		// Standard calculation với diffInMonths
		// 「休職期間は年度ごとに月数を年に換算の上、整数になるように切り捨てて算出」
		// Ví dụ: May 20, 2025 → March 23, 2026 = 10 tháng 3 ngày → 10 tháng
		// ========================================
		$months = $startDate->diffInMonths($endDate);

		// ========================================
		// Pattern 3: Check remaining period for complete short month
		// Kiểm tra phần dư có tạo thành 1 tháng đầy đủ không
		// Đặc biệt cho các tháng ngắn như tháng 2
		// ========================================
		$afterMonths = $startDate->copy()->addMonths($months);

		// Nếu sau khi cộng $months tháng vẫn chưa đến endDate
		// Kiểm tra xem phần còn lại có phải là 1 tháng đầy đủ không
		if ($afterMonths->lte($endDate)) {
			// Nếu phần còn lại bắt đầu từ ngày 1 và kết thúc vào ngày cuối cùng của tháng đó
			if ($afterMonths->day === 1
				&& $endDate->day === $endDate->daysInMonth
				&& $afterMonths->isSameMonth($endDate)) {
				$months += 1;
			}
		}

		return (int) $months;
	}
	
	private function convertMonthsToYear($months)
	{
		return round(($months / 12), 1);
	}

	/**
	 * Format total months as "X年Xヶ月" display string
	 * @param int $totalMonths Total months
	 * @return string Formatted display string
	 */
	private function formatYearsMonths($totalMonths)
	{
		$totalMonths = (int) $totalMonths;
		$years = floor($totalMonths / 12);
		$months = $totalMonths % 12;
		return $years . '年' . $months . 'ヶ月';
	}

	/**
	 * Calculate working period in total months (inclusive)
	 * Counts complete calendar months from start month to end month
	 * Example: April 2015 to March 2025 = 120 months (10 years)
	 * @param Carbon $startDate
	 * @param Carbon $endDate
	 * @return int Total months
	 */
	private function calculateWorkingMonths(Carbon $startDate, Carbon $endDate)
	{
		// Count calendar months from start to end (inclusive)
		// Formula: (endYear - startYear) * 12 + (endMonth - startMonth) + 1
		$startYear = $startDate->year;
		$startMonth = $startDate->month;
		$endYear = $endDate->year;
		$endMonth = $endDate->month;

		return (($endYear - $startYear) * 12) + ($endMonth - $startMonth) + 1;
	}
	
	private function calculatePointMonthsBetween($fromDate, $toDate, $point = 0)
	{
		$startDate = $fromDate instanceof Carbon ? $fromDate : Carbon::parse($fromDate);
		$endDate = $toDate instanceof Carbon ? $toDate : Carbon::parse($toDate);
		$months = $startDate->floatDiffInMonths($endDate);
		$months = round($months, 1);
		if ($point === 0) return 0;
		$pointPerMonth = $point / 12;
		
		return round($months * $pointPerMonth, 2);
	}
	
	private function calculatePointMonthsWithLeaveAdjustment($fromDate, $toDate, $point = 0, $employee = null)
	{
		if ($fromDate === null || $toDate === null || !$employee) return 0;
		$startDateTemp = $fromDate instanceof Carbon ? $fromDate : Carbon::parse($fromDate);
		$startDate = $startDateTemp->startOfMonth();
		$endDate = $toDate instanceof Carbon ? $toDate : Carbon::parse($toDate);
		$totalMonths = $startDate->floatDiffInMonths($endDate);
		$totalMonths = round($totalMonths, 1);
		
		if ($point === 0) return 0;
		$pointPerMonth = $point / 12;
		
		// Kiểm tra lịch sử nghỉ việc
		$affectedMonths = 0;
		foreach ($employee->leaveHistories as $leave) {
			$leaveStartDate = $leave->from_date ? Carbon::parse($leave->from_date) : null;
			$leaveEndDate = $leave->to_date ? Carbon::parse($leave->to_date) : null;
			if (!$leaveStartDate || !$leaveEndDate) continue;
			
			// Kiểm tra xem thời gian nghỉ có trùng với khoảng thời gian truyền vào không
			$overlap = $this->checkTimeRangeOverlap($leaveStartDate, $leaveEndDate, $startDate, $endDate);
			if (!$overlap) continue;
			
			// Tính số tháng nghỉ trong khoảng thời gian trùng lặp
			$leaveMonths = $this->calculateMonthsBetween($overlap['start'], $overlap['end']);
			
			// Tính số tháng bị ảnh hưởng dựa trên tenure_calculation_rate
			if ($leave->leaveType && $leave->leaveType->tenure_calculation_rate < 100) {
				$affectedMonths += floor($leaveMonths * (100 - $leave->leaveType->tenure_calculation_rate) / 100);
			}
		}
		
		// Tính số tháng hợp lệ
		$validMonths = max(0, $totalMonths - $affectedMonths);
		$validMonths = round($validMonths, 1);
		
		// Tính điểm dựa trên số tháng hợp lệ
		return round($validMonths * $pointPerMonth, 2);
	}
	
	private function calculateRateFromYears($workingYears, $payouts)
	{
		$sortedPayouts = collect($payouts)->sortBy('years')->values();
		$rate = 0;
		foreach ($sortedPayouts as $payout) {
			if ($workingYears >= $payout['years']) {
				$rate = $payout['rate'];
			} else {
				break;
			}
		}
		
		return $rate;
	}
	
	private function calculateTenurePoints($workingYears, $pointTable = [])
	{
		if (count($pointTable) === 0 || $workingYears === 0) return 0;
		if (!isset($pointTable[0])) $pointTable = [0 => 0] + $pointTable;
		
		$fullYears = floor($workingYears);
		$remainingYear = $workingYears - $fullYears;
		$totalPoints = 0;
		$maxYear = max(array_keys($pointTable));
		
		if ($fullYears == 0 && $remainingYear > 0) {
			return round($pointTable[1] * $remainingYear, 2);
		}
		
		for ($year = 1; $year <= $fullYears; $year++) {
			$currentYear = min($year, $maxYear);
			$totalPoints += $pointTable[$currentYear];
		}
		
		if ($remainingYear > 0) {
			$nextYear = min($fullYears + 1, $maxYear);
			if (isset($pointTable[$nextYear])) {
				$totalPoints += $pointTable[$nextYear] * $remainingYear;
			}
		}
		
		return round($totalPoints, 2);
	}
	
	private function calculateTenurePointsDetail($workingYears, array $pointTable)
	{
		if (count($pointTable) === 0 || $workingYears === 0) return [];
		if (!isset($pointTable[0])) $pointTable = [0 => 1] + $pointTable;
		
		$fullYears = floor($workingYears);
		$remainingYear = $workingYears - $fullYears;
		$maxYear = max(array_keys($pointTable));
		
		$details = [];
		$accumulatedPoints = 0;
		
		for ($year = 1; $year <= $fullYears; $year++) {
			$currentYear = min($year, $maxYear);
			$yearPoint = $pointTable[$currentYear];
			$accumulatedPoints += $yearPoint;
			
			$details[] = [
				'year'              => $year,
				'point_rate'        => $yearPoint,
				'year_point'        => $yearPoint,
				'accumulated_point' => round($accumulatedPoints, 2)
			];
		}
		
		if ($remainingYear > 0) {
			$nextYear = min($fullYears + 1, $maxYear);
			$yearPoint = $pointTable[$nextYear];
			$partialPoint = round($yearPoint * $remainingYear, 2);
			$accumulatedPoints += $partialPoint;
			
			$details[] = [
				'year'              => round($workingYears, 1),
				'point_rate'        => $yearPoint,
				'year_point'        => $partialPoint,
				'accumulated_point' => round($accumulatedPoints, 2)
			];
		}
		
		return $details;
	}
	
	/**
	 * Liệt kê danh sách các năm tài chính trong khoảng thời gian
	 * @param string|Carbon $startDate Ngày bắt đầu
	 * @param string|Carbon|null $endDate Ngày kết thúc (mặc định là năm tài chính hiện tại)
	 * @return array Mảng chứa thông tin các năm tài chính
	 */
	private function listFiscalYears($startDate, $endDate = null)
	{
		$startDate = $startDate instanceof Carbon ? $startDate : Carbon::parse($startDate);
		$endDate = $endDate instanceof Carbon ? $endDate : Carbon::parse($endDate);
		$fiscalYears = [];
		$currentDate = $startDate->copy();
		
		while ($currentDate->lessThanOrEqualTo($endDate)) {
			$currentYear = $currentDate->year;
			$fiscalYearEnd = Carbon::create($currentYear, 3, 31);
			$nextFiscalStart = Carbon::create($currentYear, 4, 1);
			
			if ($currentDate->lessThanOrEqualTo($fiscalYearEnd)) {
				$periodEnd = min($endDate, $fiscalYearEnd);
				$fiscalYears[] = [
					'fiscal_year' => $currentYear - 1,
					'start_date'  => $currentDate->format('Y-m-d'),
					'end_date'    => $periodEnd->format('Y-m-d')
				];
				$currentDate = $nextFiscalStart->copy();
			} else {
				$nextYearEnd = Carbon::create($currentYear + 1, 3, 31);
				$periodEnd = min($endDate, $nextYearEnd);
				$fiscalYears[] = [
					'fiscal_year' => $currentYear,
					'start_date'  => $currentDate->format('Y-m-d'),
					'end_date'    => $periodEnd->format('Y-m-d')
				];
				$currentDate = $nextYearEnd->addDay();
			}
		}
		
		return $fiscalYears;
	}
	
	/**
	 * Lấy danh sách cấp bậc theo năm tài chính của nhân viên
	 * @param Employee $employee Đối tượng nhân viên
	 * @return array Danh sách cấp bậc theo năm tài chính
	 */
	private function getLevelHistoriesByFiscalYear(Employee $employee)
	{
		$fiscalYears = $this->listFiscalYears($this->_startDate, $this->_endDate);
		$levelHistories = $employee->levelHistories->sortBy('from_date');
		$result = [];
		
		// Nếu không có lịch sử cấp bậc nhưng có cấp bậc hiện tại
		if ($levelHistories->isEmpty() && $employee->level) {
			$levelPointPerYear = $this->calculatePointBySalaryGrade($employee->salary_grade, $employee->level->details);
			foreach ($fiscalYears as $fiscalYear) {
				$fiscalStart = Carbon::parse($fiscalYear['start_date']);
				$fiscalEnd = Carbon::parse($fiscalYear['end_date']);
				
				$result[] = [
					'fiscal_year'  => $fiscalYear['fiscal_year'],
					'from_date'    => $fiscalStart->format('Y/m/d'),
					'to_date'      => $fiscalEnd->format('Y/m/d'),
					'parent_name'  => $employee->level->parent ? $employee->level->parent->name : null,
					'name'         => $employee->level->name,
					'salary_grade' => $employee->salary_grade,
					'point_value'  => $levelPointPerYear,
					'point'        => $this->calculatePointMonthsWithLeaveAdjustment($fiscalStart->format('Y/m/d'), $fiscalEnd->format('Y/m/d'), $levelPointPerYear, $employee),
					//'point'        => $this->calculatePointMonthsBetween($fiscalStart->format('Y/m/d'), $fiscalEnd->format('Y/m/d'), $levelPointPerYear),
				];
			}
			
			return $result;
		}
		
		// Trường hợp chỉ có một bản ghi lịch sử
		if ($levelHistories->count() === 1) {
			$singleHistory = $levelHistories->first();
			$historyStart = Carbon::parse($singleHistory->from_date);
			$historyEnd = Carbon::parse($singleHistory->to_date);
			
			foreach ($fiscalYears as $fiscalYear) {
				$fiscalStart = Carbon::parse($fiscalYear['start_date']);
				$fiscalEnd = Carbon::parse($fiscalYear['end_date']);
				
				if ($fiscalStart->lessThanOrEqualTo($historyEnd) && $fiscalEnd->greaterThanOrEqualTo($historyStart)) {
					$effectiveStart = $historyStart->max($fiscalStart);
					$effectiveEnd = $historyEnd->min($fiscalEnd);
					$levelPointPerYear = $this->calculatePointBySalaryGrade($singleHistory->salary_grade, $singleHistory->level->details);
					
					$result[] = [
						'fiscal_year'  => $fiscalYear['fiscal_year'],
						'from_date'    => $effectiveStart->format('Y/m/d'),
						'to_date'      => $effectiveEnd->format('Y/m/d'),
						'parent_name'  => $singleHistory->level->parent ? $singleHistory->level->parent->name : null,
						'name'         => $singleHistory->level->name,
						'salary_grade' => $singleHistory->salary_grade,
						'point_value'  => $levelPointPerYear,
						'point'        => $this->calculatePointMonthsWithLeaveAdjustment($effectiveStart->format('Y/m/d'), $effectiveEnd->format('Y/m/d'), $levelPointPerYear, $employee),
						//'point'        => $this->calculatePointMonthsBetween($effectiveStart->format('Y/m/d'), $effectiveEnd->format('Y/m/d'), $levelPointPerYear),
					];
				}
				
				// Xử lý năm tài chính hiện tại nếu nhân viên đang làm việc
				if (!$employee->resigned_date && $employee->level && $fiscalEnd->greaterThan(Carbon::now())) {
					$lastHistory = $result[count($result) - 1];
					if (!$lastHistory || Carbon::parse($lastHistory['to_date'])->lessThan($fiscalEnd)) {
						$effectiveStart = $lastHistory ? Carbon::parse($lastHistory['to_date'])->addDay() : $fiscalStart;
						$levelPointPerYear = $this->calculatePointBySalaryGrade($employee->salary_grade, $employee->level->details);
						$subFiscalYears = $this->listFiscalYears($effectiveStart, $fiscalEnd);
						foreach ($subFiscalYears as $subFiscalYear) {
							$result[] = [
								'fiscal_year'  => $subFiscalYear['fiscal_year'],
								'from_date'    => Carbon::parse($subFiscalYear['start_date'])->format('Y/m/d'),
								'to_date'      => Carbon::parse($subFiscalYear['end_date'])->format('Y/m/d'),
								'parent_name'  => $employee->level->parent ? $employee->level->parent->name : null,
								'name'         => $employee->level->name,
								'salary_grade' => $employee->salary_grade,
								'point_value'  => $levelPointPerYear,
								'point'        => $this->calculatePointMonthsWithLeaveAdjustment(Carbon::parse($subFiscalYear['start_date'])->format('Y/m/d'), Carbon::parse($subFiscalYear['end_date'])->format('Y/m/d'), $levelPointPerYear, $employee),
								//'point'        => $this->calculatePointMonthsBetween(Carbon::parse($subFiscalYear['start_date'])->format('Y/m/d'), Carbon::parse($subFiscalYear['end_date'])->format('Y/m/d'), $levelPointPerYear),
							];
						}
					}
				}
			}
			
			return $result;
		}
		
		// Trường hợp có nhiều bản ghi lịch sử
		$processedLevels = collect();
		
		// Xử lý to_date cho các bản ghi
		$levelHistories->each(function ($history, $index) use ($levelHistories, &$processedLevels) {
			$nextHistory = $levelHistories->get($index + 1);
			if (!$history->to_date) {
				if ($nextHistory) {
					// Nếu có bản ghi tiếp theo, to_date là ngày trước from_date của bản ghi tiếp theo
					$history->to_date = Carbon::parse($nextHistory->from_date)->subDay()->format('Y-m-d');
				} else {
					// Nếu là bản ghi cuối cùng
					$history->to_date = $this->_endDate->format('Y-m-d');
				}
			}
			$processedLevels->push($history);
		});
		
		// Xử lý từng năm tài chính
		foreach ($fiscalYears as $fiscalYear) {
			$fiscalStart = Carbon::parse($fiscalYear['start_date']);
			$fiscalEnd = Carbon::parse($fiscalYear['end_date']);
			
			// Tìm các cấp bậc trong năm tài chính này
			$levelsInYear = $levelHistories->filter(function ($level) use ($fiscalStart, $fiscalEnd) {
				$levelStart = Carbon::parse($level->from_date);
				$levelEnd = Carbon::parse($level->to_date);
				
				//return $levelStart->lessThanOrEqualTo($fiscalEnd) && $levelEnd->greaterThanOrEqualTo($fiscalStart);
				return ($levelStart->lessThanOrEqualTo($fiscalEnd) && $levelEnd->greaterThanOrEqualTo($fiscalStart))
					|| ($levelStart->lessThanOrEqualTo($fiscalEnd) && $levelStart->greaterThanOrEqualTo($fiscalStart));
			});
			
			foreach ($levelsInYear as $level) {
				$levelStart = Carbon::parse($level->from_date);
				$levelEnd = Carbon::parse($level->to_date);
				$effectiveStart = $levelStart->max($fiscalStart);
				$effectiveEnd = $levelEnd->min($fiscalEnd);
				$levelPointPerYear = $this->calculatePointBySalaryGrade($level->salary_grade, $level->level->details);
				
				$result[] = [
					'fiscal_year'  => $fiscalYear['fiscal_year'],
					'from_date'    => $effectiveStart->format('Y/m/d'),
					'to_date'      => $effectiveEnd->format('Y/m/d'),
					'parent_name'  => $level->level->parent ? $level->level->parent->name : null,
					'name'         => $level->level->name,
					'salary_grade' => $level->salary_grade,
					'point_value'  => $levelPointPerYear,
					'point'        => $this->calculatePointMonthsWithLeaveAdjustment($effectiveStart->format('Y/m/d'), $effectiveEnd->format('Y/m/d'), $levelPointPerYear, $employee),
					//'point'        => $this->calculatePointMonthsBetween($effectiveStart->format('Y/m/d'), $effectiveEnd->format('Y/m/d'), $levelPointPerYear),
				];
			}
			
			// Xử lý năm tài chính hiện tại nếu nhân viên đang làm việc
			if (!$employee->resigned_date && $employee->level && $fiscalEnd->greaterThan(Carbon::now())) {
				$lastHistory = $result[count($result) - 1];
				if (!$lastHistory || Carbon::parse($lastHistory['to_date'])->lessThan($fiscalEnd)) {
					$effectiveStart = $lastHistory ? Carbon::parse($lastHistory['to_date'])->addDay() : $fiscalStart;
					$levelPointPerYear = $this->calculatePointBySalaryGrade($employee->salary_grade, $employee->level->details);
					$subFiscalYears = $this->listFiscalYears($effectiveStart, $fiscalEnd);
					foreach ($subFiscalYears as $subFiscalYear) {
						$result[] = [
							'fiscal_year'  => $subFiscalYear['fiscal_year'],
							'from_date'    => Carbon::parse($subFiscalYear['start_date'])->format('Y/m/d'),
							'to_date'      => Carbon::parse($subFiscalYear['end_date'])->format('Y/m/d'),
							'parent_name'  => $employee->level->parent ? $employee->level->parent->name : null,
							'name'         => $employee->level->name,
							'salary_grade' => $employee->salary_grade,
							'point_value'  => $levelPointPerYear,
							'point'        => $this->calculatePointMonthsWithLeaveAdjustment(Carbon::parse($subFiscalYear['start_date'])->format('Y/m/d'), Carbon::parse($subFiscalYear['end_date'])->format('Y/m/d'), $levelPointPerYear, $employee),
							//'point'        => $this->calculatePointMonthsBetween(Carbon::parse($subFiscalYear['start_date'])->format('Y/m/d'), Carbon::parse($subFiscalYear['end_date'])->format('Y/m/d'), $levelPointPerYear),
						];
					}
				}
			}
		}
		
		return $result;
	}
	
	/**
	 * Lấy danh sách chức vụ theo năm tài chính của nhân viên
	 * @param Employee $employee Đối tượng nhân viên
	 * @return array Danh sách chức vụ theo năm tài chính
	 */
	private function getPositionHistoriesByFiscalYear(Employee $employee)
	{
		$fiscalYears = $this->listFiscalYears($this->_startDate, $this->_endDate);
		$positionHistories = $employee->positionHistories->sortBy('from_date');
		$result = [];
		
		// Nếu không có lịch sử chức vụ nhưng có chức vụ hiện tại, áp dụng cho toàn bộ thời gian
		if ($positionHistories->isEmpty() && $employee->position) {
			foreach ($fiscalYears as $fiscalYear) {
				$fiscalStart = Carbon::parse($fiscalYear['start_date']);
				$fiscalEnd = Carbon::parse($fiscalYear['end_date']);
				
				$result[] = [
					'fiscal_year'       => $fiscalYear['fiscal_year'],
					'from_date'         => $fiscalStart->format('Y/m/d'),
					'to_date'           => $fiscalEnd->format('Y/m/d'),
					'concurrent_duties' => $employee->position->concurrent_duties,
					'issued_by'         => $employee->position->issued_by,
					'name'              => $employee->position->name,
					'point_value'       => $employee->position->point_value,
					'point'             => $this->calculatePointMonthsWithLeaveAdjustment($fiscalStart->format('Y/m/d'), $fiscalEnd->format('Y/m/d'), $employee->position->point_value, $employee),
					//'point'             => $this->calculatePointMonthsBetween($fiscalStart->format('Y/m/d'), $fiscalEnd->format('Y/m/d'), $employee->position->point_value),
				];
			}
			
			return $result;
		}
		
		// Trường hợp chỉ có một bản ghi lịch sử
		if ($positionHistories->count() === 1) {
			$singleHistory = $positionHistories->first();
			$historyStart = Carbon::parse($singleHistory->from_date);
			$historyEnd = Carbon::parse($singleHistory->to_date);
			
			foreach ($fiscalYears as $fiscalYear) {
				$fiscalStart = Carbon::parse($fiscalYear['start_date']);
				$fiscalEnd = Carbon::parse($fiscalYear['end_date']);
				
				if ($fiscalStart->lessThanOrEqualTo($historyEnd) && $fiscalEnd->greaterThanOrEqualTo($historyStart)) {
					$effectiveStart = $historyStart->max($fiscalStart);
					$effectiveEnd = $historyEnd->min($fiscalEnd);
					
					$result[] = [
						'fiscal_year' => $fiscalYear['fiscal_year'],
						'from_date'   => $effectiveStart->format('Y/m/d'),
						'to_date'     => $effectiveEnd->format('Y/m/d'),
						'name'        => $singleHistory->position->name,
						'point_value' => $singleHistory->position->point_value,
						'point'       => $this->calculatePointMonthsWithLeaveAdjustment($effectiveStart->format('Y/m/d'), $effectiveEnd->format('Y/m/d'), $singleHistory->position->point_value, $employee),
						//'point'       => $this->calculatePointMonthsBetween($effectiveStart->format('Y/m/d'), $effectiveEnd->format('Y/m/d'), $singleHistory->position->point_value),
					];
				}
				
				// Xử lý năm tài chính hiện tại nếu nhân viên đang làm việc
				if (!$employee->resigned_date && $employee->position && $fiscalEnd->greaterThan(Carbon::now())) {
					$lastHistory = $result[count($result) - 1];
					if (!$lastHistory || Carbon::parse($lastHistory['to_date'])->lessThan($fiscalEnd)) {
						$effectiveStart = $lastHistory ? Carbon::parse($lastHistory['to_date'])->addDay() : $fiscalStart;
						$subFiscalYears = $this->listFiscalYears($effectiveStart, $fiscalEnd);
						foreach ($subFiscalYears as $subFiscalYear) {
							$result[] = [
								'fiscal_year' => $subFiscalYear['fiscal_year'],
								'from_date'   => Carbon::parse($subFiscalYear['start_date'])->format('Y/m/d'),
								'to_date'     => Carbon::parse($subFiscalYear['end_date'])->format('Y/m/d'),
								'name'        => $employee->position->name,
								'point_value' => $employee->position->point_value,
								'point'       => $this->calculatePointMonthsWithLeaveAdjustment(Carbon::parse($subFiscalYear['start_date'])->format('Y/m/d'), Carbon::parse($subFiscalYear['end_date'])->format('Y/m/d'), $employee->position->point_value, $employee),
								//'point'       => $this->calculatePointMonthsBetween(Carbon::parse($subFiscalYear['start_date'])->format('Y/m/d'), Carbon::parse($subFiscalYear['end_date'])->format('Y/m/d'), $employee->position->point_value),
							];
						}
					}
				}
			}
			
			return $result;
		}
		
		// Trường hợp có nhiều bản ghi lịch sử
		$processedHistories = collect();
		
		// Xử lý to_date cho các bản ghi
		$positionHistories->each(function ($history, $index) use ($positionHistories, &$processedHistories) {
			$nextHistory = $positionHistories->get($index + 1);
			if (!$history->to_date) {
				if ($nextHistory) {
					// Nếu có bản ghi tiếp theo, to_date là ngày trước from_date của bản ghi tiếp theo
					$history->to_date = Carbon::parse($nextHistory->from_date)->subDay()->format('Y-m-d');
				} else {
					// Nếu là bản ghi cuối cùng
					$history->to_date = $this->_endDate->format('Y-m-d');
				}
			}
			$processedHistories->push($history);
		});
		
		// Xử lý từng năm tài chính
		foreach ($fiscalYears as $fiscalYear) {
			$fiscalStart = Carbon::parse($fiscalYear['start_date']);
			$fiscalEnd = Carbon::parse($fiscalYear['end_date']);
			
			// Tìm các chức vụ trong năm tài chính này
			$positionsInYear = $processedHistories->filter(function ($position) use ($fiscalStart, $fiscalEnd) {
				$positionStart = Carbon::parse($position->from_date);
				$positionEnd = Carbon::parse($position->to_date);
				
				//return $positionStart->lessThanOrEqualTo($fiscalEnd) && $positionEnd->greaterThanOrEqualTo($fiscalStart);
				return ($positionStart->lessThanOrEqualTo($fiscalEnd) && $positionEnd->greaterThanOrEqualTo($fiscalStart))
					|| ($positionStart->lessThanOrEqualTo($fiscalEnd) && $positionStart->greaterThanOrEqualTo($fiscalStart));
			});
			
			foreach ($positionsInYear as $position) {
				$positionStart = Carbon::parse($position->from_date);
				$positionEnd = Carbon::parse($position->to_date);
				$effectiveStart = $positionStart->max($fiscalStart);
				$effectiveEnd = $positionEnd->min($fiscalEnd);
				
				$result[] = [
					'fiscal_year' => $fiscalYear['fiscal_year'],
					'from_date'   => $effectiveStart->format('Y/m/d'),
					'to_date'     => $effectiveEnd->format('Y/m/d'),
					'name'        => $position->position->name,
					'point_value' => $position->position->point_value,
					'point'       => $this->calculatePointMonthsWithLeaveAdjustment($effectiveStart->format('Y/m/d'), $effectiveEnd->format('Y/m/d'), $position->position->point_value, $employee),
					//'point'       => $this->calculatePointMonthsBetween($effectiveStart->format('Y/m/d'), $effectiveEnd->format('Y/m/d'), $position->position->point_value),
				];
			}
			
			// Xử lý năm tài chính hiện tại nếu nhân viên đang làm việc
			if (!$employee->resigned_date && $employee->position && $fiscalEnd->greaterThan(Carbon::now())) {
				$lastHistory = $result[count($result) - 1];
				if (!$lastHistory || Carbon::parse($lastHistory['to_date'])->lessThan($fiscalEnd)) {
					$effectiveStart = $lastHistory ? Carbon::parse($lastHistory['to_date'])->addDay() : $fiscalStart;
					$subFiscalYears = $this->listFiscalYears($effectiveStart, $fiscalEnd);
					foreach ($subFiscalYears as $subFiscalYear) {
						$result[] = [
							'fiscal_year' => $subFiscalYear['fiscal_year'],
							'from_date'   => Carbon::parse($subFiscalYear['start_date'])->format('Y/m/d'),
							'to_date'     => Carbon::parse($subFiscalYear['end_date'])->format('Y/m/d'),
							'name'        => $employee->position->name,
							'point_value' => $employee->position->point_value,
							'point'       => $this->calculatePointMonthsWithLeaveAdjustment(Carbon::parse($subFiscalYear['start_date'])->format('Y/m/d'), Carbon::parse($subFiscalYear['end_date'])->format('Y/m/d'), $employee->position->point_value, $employee),
							//'point'       => $this->calculatePointMonthsBetween(Carbon::parse($subFiscalYear['start_date'])->format('Y/m/d'), Carbon::parse($subFiscalYear['end_date'])->format('Y/m/d'), $employee->position->point_value),
						];
					}
				}
			}
		}
		
		return $result;
	}
	
	private function checkTimeRangeOverlap($checkStart, $checkEnd, $rangeStart, $rangeEnd)
	{
		// TH1: $check hoàn toàn không nằm trong $range
		if ($checkEnd->lessThan($rangeStart) || $checkStart->greaterThan($rangeEnd)) {
			return null;
		}
		
		// TH2: $checkStart nằm ngoài nhưng $checkEnd nằm trong range
		if ($checkStart->lessThan($rangeStart) &&
			$checkEnd->greaterThanOrEqualTo($rangeStart) &&
			$checkEnd->lessThanOrEqualTo($rangeEnd)) {
			return ['start' => $rangeStart, 'end' => $checkEnd];
		}
		
		// TH3: $checkEnd nằm ngoài nhưng $checkStart nằm trong range
		if ($checkEnd->greaterThan($rangeEnd) &&
			$checkStart->greaterThanOrEqualTo($rangeStart) &&
			$checkStart->lessThanOrEqualTo($rangeEnd)) {
			return ['start' => $checkStart, 'end' => $rangeEnd];
		}
		
		// TH4: cả $check nằm hoàn toàn trong $range
		if ($checkStart->greaterThanOrEqualTo($rangeStart) &&
			$checkEnd->lessThanOrEqualTo($rangeEnd)) {
			return ['start' => $checkStart, 'end' => $checkEnd];
		}
	}
	
	private function sortTimeRanges($timeArray)
	{
		if ($timeArray && count($timeArray) > 1) {
			usort($timeArray, function ($a, $b) {
				$dateA = Carbon::createFromFormat('Y/m/d', $a['to_date']);
				$dateB = Carbon::createFromFormat('Y/m/d', $b['to_date']);
				if ($dateA->equalTo($dateB)) return 0;
				return $dateA->lessThan($dateB) ? -1 : 1;
			});
		}
		
		return $timeArray;
	}
	
	/**
	 * Tính điểm dựa trên bậc lương và bảng điểm
	 * @param int|null $salaryGrade Bậc lương của nhân viên
	 * @param \Illuminate\Database\Eloquent\Collection $levelDetails Collection các chi tiết cấp bậc
	 * @return float Điểm số tương ứng với bậc lương
	 */
	private function calculatePointBySalaryGrade($salaryGrade, $levelDetails)
	{
		// Kiểm tra bậc lương null hoặc rỗng
		if ($salaryGrade === null || $salaryGrade === '') {
			return 0;
		}
		
		// Trường hợp 1: Collection rỗng
		if ($levelDetails->isEmpty()) {
			return 0;
		}
		
		// Trường hợp 2: Chỉ có 1 phần tử và không có giới hạn bậc lương
		if ($levelDetails->count() === 1) {
			$firstRecord = $levelDetails->first();
			if (empty($firstRecord->salary_grade_from) && empty($firstRecord->salary_grade_to)) {
				return (float)$firstRecord->point_value;
			}
		}
		
		// Trường hợp 3, 4, 5: Tìm điểm phù hợp theo bậc lương
		foreach ($levelDetails as $level) {
			// Trường hợp 4: Chỉ có salary_grade_from
			if (!empty($level->salary_grade_from) && empty($level->salary_grade_to)) {
				if ($salaryGrade >= $level->salary_grade_from) {
					return (float)$level->point_value;
				}
				continue;
			}
			
			// Trường hợp 5: Chỉ có salary_grade_to
			if (empty($level->salary_grade_from) && !empty($level->salary_grade_to)) {
				if ($salaryGrade <= $level->salary_grade_to) {
					return (float)$level->point_value;
				}
				continue;
			}
			
			// Trường hợp 3: Có cả from và to
			if (!empty($level->salary_grade_from) && !empty($level->salary_grade_to)) {
				if ($salaryGrade >= $level->salary_grade_from && $salaryGrade <= $level->salary_grade_to) {
					return (float)$level->point_value;
				}
			}
		}
		
		return 0;
	}
	
	function calculateWorkingYears(Carbon $startDate, Carbon $endDate) {
		$years = $startDate->diffInYears($endDate);
		$remainingMonths = $startDate->copy()->addYears($years)->floatDiffInMonths($endDate);
		$decimalYears = $remainingMonths / 12;
		$roundedDecimal = round($decimalYears, 1);
		return ($years + $roundedDecimal);
	}
}