<?php

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Models\Document;
use App\Models\Holiday;
use App\Models\Leave;
use App\Models\LeaveType;
use App\Models\User;
use App\Notifications\LeaveCancelledNotification;
use App\Notifications\LeaveRequestSubmittedNotification;
use App\Notifications\LeaveReviewedNotification;
use App\Notifications\LeaveSubmittedNotification;
use App\Notifications\LeaveWithdrawalRequestedNotification;
use App\Services\HrmsNotificationService;
use App\Services\Leave\LeaveDashboardStatsService;
use App\Services\Leave\LeaveLedgerService;
use App\Services\Leave\LeaveRuleValidator;
use App\Support\FormTextRules;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;

class LeaveController extends Controller
{
    public function index(Request $request)
    {
        $authUser = Auth::user();
        $companyId = $authUser?->company_id;
        $visibleUserIds = $authUser?->visibleStaffUserIds() ?? [];
        $query = Leave::with(['user', 'leaveType']);
        if ($companyId) {
            $query->where('company_id', $companyId);
        }
        if (! empty($visibleUserIds)) {
            $query->whereIn('user_id', $visibleUserIds);
        }
        if ($request->filled('status')) {
            $query->where('status', $request->status);
        }
        if ($request->filled('leave_type_id')) {
            $query->where('leave_type_id', (int) $request->leave_type_id);
        }
        if ($request->filled('q')) {
            $term = trim((string) $request->q);
            $query->where(function ($q) use ($term) {
                $q->where('reason', 'like', '%'.$term.'%')
                    ->orWhereHas('user', fn ($uq) => $uq->where('name', 'like', '%'.$term.'%'))
                    ->orWhereHas('leaveType', fn ($tq) => $tq->where('name', 'like', '%'.$term.'%'));
            });
        }

        $leaves = $query->orderByDesc('created_at')->paginate(15)->withQueryString();
        $today = now()->toDateString();
        $baseCountQuery = Leave::query();
        if ($companyId) {
            $baseCountQuery->where('company_id', $companyId);
        }
        if (! empty($visibleUserIds)) {
            $baseCountQuery->whereIn('user_id', $visibleUserIds);
        }

        $stats = [
            'pending' => (clone $baseCountQuery)->where('status', 'pending')->count(),
            'approved_today' => (clone $baseCountQuery)->where('status', 'approved')->whereDate('updated_at', $today)->count(),
            'rejected' => (clone $baseCountQuery)->where('status', 'rejected')->count(),
            'on_leave_today' => (clone $baseCountQuery)->whereIn('status', Leave::approvedLikeStatuses())->whereDate('start_date', '<=', $today)->whereDate('end_date', '>=', $today)->count(),
        ];

        $leaveTypes = LeaveType::query()
            ->when($companyId, fn ($q) => $q->where('company_id', $companyId))
            ->orderBy('name')
            ->get(['id', 'name']);

        return view('leaves.index', compact('leaves', 'stats', 'leaveTypes'));
    }

    public function create(LeaveLedgerService $ledger)
    {
        $authUser = Auth::user();
        $companyId = $authUser?->company_id;
        $visibleUserIds = $authUser?->visibleStaffUserIds() ?? [];
        $users = User::query()->forActiveDirectory();
        $leaveTypes = LeaveType::query();

        if ($companyId) {
            $users->where('company_id', $companyId);
            $leaveTypes->where('company_id', $companyId);
        }
        if (! empty($visibleUserIds)) {
            $users->whereIn('id', $visibleUserIds);
        }

        return view('leaves.create', array_merge([
            'users' => $users->orderBy('name')->get(),
            'leaveTypes' => $leaveTypes->orderBy('name')->get(),
        ], $this->createSidebarData($authUser, $ledger)));
    }

    public function store(Request $request, LeaveRuleValidator $ruleValidator, LeaveLedgerService $ledger)
    {
        $authUser = Auth::user();
        $companyId = $authUser?->company_id;
        $visibleUserIds = $authUser?->visibleStaffUserIds() ?? [];
        $validated = $request->validate([
            'user_id' => [
                'required',
                Rule::exists('users', 'id')->where(function ($q) use ($companyId) {
                    $q->where('user_type', User::USER_TYPE_STAFF);
                    if ($companyId) {
                        $q->where('company_id', $companyId);
                    }
                }),
                Rule::in($visibleUserIds),
            ],
            'leave_type_id' => [
                'required',
                Rule::exists('leave_types', 'id')->where(function ($q) use ($companyId) {
                    if ($companyId) {
                        $q->where('company_id', $companyId);
                    }
                }),
            ],
            'start_date' => ['required', 'date'],
            'end_date' => ['required', 'date', 'after_or_equal:start_date'],
            'reason' => FormTextRules::notNumericOnly(true, 1000),
            'is_half_day' => ['nullable', 'boolean'],
            'half_leave' => ['required_if:is_half_day,1', 'nullable', Rule::in(['first_half', 'second_half'])],
            'is_paid' => ['nullable', 'boolean'],
            'attachment' => ['nullable', 'file', 'max:10240', 'mimes:pdf,jpg,jpeg,png,doc,docx'],
        ], FormTextRules::messages());

        $startDate = \Carbon\Carbon::parse($validated['start_date']);
        $endDate = \Carbon\Carbon::parse($validated['end_date']);

        $isHalfDay = (bool) ($validated['is_half_day'] ?? false);
        if ($isHalfDay && ! $startDate->isSameDay($endDate)) {
            throw ValidationException::withMessages([
                'is_half_day' => 'Half-day leave is allowed only for single-day leave requests.',
            ]);
        }
        $halfLeave = $isHalfDay ? $validated['half_leave'] : 'before_break';

        $user = User::query()
            ->forActiveDirectory()
            ->when($companyId, fn ($q) => $q->where('company_id', $companyId))
            ->whereIn('id', $visibleUserIds)
            ->findOrFail($validated['user_id']);

        $leaveType = LeaveType::query()
            ->when($companyId, fn ($q) => $q->where('company_id', $companyId))
            ->findOrFail($validated['leave_type_id']);

        $calc = $ruleValidator->validateForCreate($request, $user, $leaveType, $startDate, $endDate, $isHalfDay);

        $leave = Leave::create([
            'company_id' => $companyId,
            'user_id' => $validated['user_id'],
            'leave_type_id' => $validated['leave_type_id'],
            'start_date' => $validated['start_date'],
            'end_date' => $validated['end_date'],
            'total_days' => $calc['chargeable_days'],
            'is_half_day' => $isHalfDay,
            'half_leave' => $halfLeave,
            'reason' => trim((string) $validated['reason']) !== '' ? $validated['reason'] : 'N/A',
            'remark' => null,
            'is_paid' => $request->boolean('is_paid', (bool) $leaveType->is_paid),
            'status' => 'pending',
        ]);

        try {
            $ledger->holdPending($leave);
        } catch (\InvalidArgumentException $e) {
            $leave->delete();

            return back()->withInput()->withErrors(['start_date' => $e->getMessage()]);
        }

        if ($request->file('attachment')) {
            $file = $request->file('attachment');
            $path = $file->store('documents/' . ($companyId ?? 'shared'), 'local');
            Document::create([
                'company_id' => $companyId,
                'name' => 'Leave Attachment - ' . ($user->employee_number ?: ('EMP' . $user->id)) . ' - ' . now()->format('YmdHis'),
                'type' => 'leave_attachment',
                'path' => $path,
                'documentable_type' => Leave::class,
                'documentable_id' => $leave->id,
                'uploaded_by' => Auth::id(),
            ]);
        }

        $leave->load(['user', 'leaveType']);
        app(HrmsNotificationService::class)->notifyLeaveApprovers(
            $user,
            new LeaveSubmittedNotification($leave)
        );
        $user->notify(new LeaveRequestSubmittedNotification($leave));

        return redirect()->route('leaves.index')->with('success', 'Leave request created successfully. Approvers have been notified.');
    }

    public function edit(Leave $leave, LeaveLedgerService $ledger)
    {
        $this->authorize('update', $leave);
        $leave->loadMissing('user');

        $authUser = Auth::user();
        $companyId = $authUser?->company_id;
        $visibleUserIds = $authUser?->visibleStaffUserIds() ?? [];
        $users = User::query()->forActiveDirectory();
        $leaveTypes = LeaveType::query();

        if ($companyId) {
            $users->where('company_id', $companyId);
            $leaveTypes->where('company_id', $companyId);
        }
        if (! empty($visibleUserIds)) {
            $users->whereIn('id', $visibleUserIds);
        }

        $subjectUser = $leave->user ?? $authUser;

        return view('leaves.create', array_merge([
            'users' => $users->orderBy('name')->get(),
            'leaveTypes' => $leaveTypes->orderBy('name')->get(),
            'leave' => $leave,
        ], $this->createSidebarData($subjectUser ?: $authUser, $ledger)));
    }

    public function update(Request $request, Leave $leave, LeaveRuleValidator $ruleValidator, LeaveLedgerService $ledger)
    {
        $this->authorize('update', $leave);

        $authUser = Auth::user();
        $companyId = $authUser?->company_id;
        $validated = $request->validate([
            'leave_type_id' => [
                'required',
                Rule::exists('leave_types', 'id')->where(function ($q) use ($companyId) {
                    if ($companyId) {
                        $q->where('company_id', $companyId);
                    }
                }),
            ],
            'start_date' => ['required', 'date'],
            'end_date' => ['required', 'date', 'after_or_equal:start_date'],
            'reason' => FormTextRules::notNumericOnly(true, 1000),
            'is_half_day' => ['nullable', 'boolean'],
            'half_leave' => ['required_if:is_half_day,1', 'nullable', Rule::in(['first_half', 'second_half'])],
            'is_paid' => ['nullable', 'boolean'],
            'attachment' => ['nullable', 'file', 'max:10240', 'mimes:pdf,jpg,jpeg,png,doc,docx'],
        ], FormTextRules::messages());

        $startDate = \Carbon\Carbon::parse($validated['start_date']);
        $endDate = \Carbon\Carbon::parse($validated['end_date']);
        $isHalfDay = (bool) ($validated['is_half_day'] ?? false);
        if ($isHalfDay && ! $startDate->isSameDay($endDate)) {
            throw ValidationException::withMessages([
                'is_half_day' => 'Half-day leave is allowed only for single-day leave requests.',
            ]);
        }
        $halfLeave = $isHalfDay ? $validated['half_leave'] : 'before_break';

        $user = User::query()
            ->forActiveDirectory()
            ->when($companyId, fn ($q) => $q->where('company_id', $companyId))
            ->findOrFail($leave->user_id);

        $leaveType = LeaveType::query()
            ->when($companyId, fn ($q) => $q->where('company_id', $companyId))
            ->findOrFail($validated['leave_type_id']);

        $calc = $ruleValidator->validateForCreate($request, $user, $leaveType, $startDate, $endDate, $isHalfDay, $leave);

        $previousDays = round((float) $leave->total_days, 2);
        $previousTypeId = (int) $leave->leave_type_id;
        $previousYear = $ledger->leaveYear(\Carbon\Carbon::parse($leave->start_date));
        $newYear = $ledger->leaveYear($startDate);
        $newDays = round((float) $calc['chargeable_days'], 2);
        $ledgerChanged = $previousDays !== $newDays
            || $previousTypeId !== (int) $leaveType->id
            || $previousYear !== $newYear;

        $reference = 'leave:'.$leave->id.':'.str_replace('-', '', (string) Str::uuid());

        try {
            DB::transaction(function () use ($leave, $ledger, $validated, $calc, $isHalfDay, $halfLeave, $request, $leaveType, $ledgerChanged, $reference, $companyId, $user) {
                if ($ledgerChanged) {
                    $ledger->releasePending($leave, 'pending_release:'.$reference);
                }

                $leave->update([
                    'leave_type_id' => $validated['leave_type_id'],
                    'start_date' => $validated['start_date'],
                    'end_date' => $validated['end_date'],
                    'total_days' => $calc['chargeable_days'],
                    'is_half_day' => $isHalfDay,
                    'half_leave' => $halfLeave,
                    'reason' => trim((string) $validated['reason']) !== '' ? $validated['reason'] : 'N/A',
                    'is_paid' => $request->boolean('is_paid', (bool) $leaveType->is_paid),
                ]);

                if ($ledgerChanged) {
                    $leave->unsetRelation('leaveType');
                    $leave->unsetRelation('user');
                    $leave->load(['user', 'leaveType']);
                    $ledger->holdPending($leave, 'pending_hold:'.$reference);
                }

                if ($request->file('attachment')) {
                    $file = $request->file('attachment');
                    $path = $file->store('documents/'.($companyId ?? 'shared'), 'local');
                    Document::create([
                        'company_id' => $companyId,
                        'name' => 'Leave Attachment - '.($user->employee_number ?: ('EMP'.$user->id)).' - '.now()->format('YmdHis'),
                        'type' => 'leave_attachment',
                        'path' => $path,
                        'documentable_type' => Leave::class,
                        'documentable_id' => $leave->id,
                        'uploaded_by' => Auth::id(),
                    ]);
                }
            });
        } catch (\InvalidArgumentException $e) {
            return back()->withInput()->withErrors(['start_date' => $e->getMessage()]);
        }

        return redirect()->route('leaves.index')->with('success', 'Leave request updated.');
    }

    public function destroy(Leave $leave, LeaveLedgerService $ledger)
    {
        $this->authorize('delete', $leave);

        $leave->load(['user', 'leaveType']);
        $user = $leave->user;
        if ($user) {
            app(HrmsNotificationService::class)->notifyLeaveApprovers(
                $user,
                new LeaveCancelledNotification($leave)
            );
        }

        try {
            $ledger->releasePending($leave);
        } catch (\Throwable) {
            // Leave may not have a ledger hold; still allow cancel.
        }

        $leave->delete();

        return redirect()->route('leaves.index')->with('success', 'Leave request cancelled.');
    }

    public function withdraw(Request $request, Leave $leave, LeaveLedgerService $ledger)
    {
        $this->authorize('withdraw', $leave);

        $validated = $request->validate([
            'withdrawal_reason' => array_merge(
                FormTextRules::notNumericOnly(true, 1000),
                ['min:3']
            ),
        ], FormTextRules::messages());

        $leave->load(['user', 'leaveType']);

        $leave->update([
            'status' => 'withdrawal_pending',
            'withdrawal_reason' => $validated['withdrawal_reason'],
        ]);

        $user = $leave->user;
        if ($user) {
            app(HrmsNotificationService::class)->notifyLeaveApprovers(
                $user,
                new LeaveWithdrawalRequestedNotification($leave->fresh(['user', 'leaveType']))
            );
        }

        app(\App\Services\AuditService::class)->log('leave.withdrawal_requested', $leave, [
            'withdrawal_reason' => $validated['withdrawal_reason'],
        ]);

        return redirect()->route('leaves.index')->with('success', 'Withdrawal requested. Waiting for admin approval.');
    }

    public function reviewWithdraw(Request $request, Leave $leave, LeaveLedgerService $ledger)
    {
        $reviewer = Auth::user();
        $companyId = $reviewer?->company_id;
        if ($companyId && $leave->company_id !== $companyId) {
            abort(403);
        }

        $this->authorize('approve', $leave);

        if ($leave->status !== 'withdrawal_pending') {
            return redirect()->back()->withErrors(['status' => 'Only withdrawal requests can be reviewed.']);
        }

        $validated = $request->validate([
            'decision' => ['required', Rule::in(['accepted', 'rejected'])],
            'remark' => ['nullable', 'string', 'max:1000'],
        ]);

        $leave->load(['user', 'leaveType']);
        $decision = $validated['decision'];
        $remark = trim((string) ($validated['remark'] ?? ''));

        if ($decision === 'accepted') {
            $ledger->reverseApproved($leave);
            $leave->update([
                'status' => 'cancelled',
                'remark' => $remark !== '' ? $remark : $leave->remark,
            ]);
            $outcome = 'withdrawal accepted';
            $auditAction = 'leave.withdrawal_accepted';
        } else {
            $leave->update([
                'status' => 'approved',
                'withdrawal_reason' => null,
                'remark' => $remark !== '' ? $remark : $leave->remark,
            ]);
            $outcome = 'withdrawal rejected';
            $auditAction = 'leave.withdrawal_rejected';
        }

        $leave->load(['user', 'leaveType']);
        $leave->user?->notify(new LeaveReviewedNotification($leave, $outcome));

        app(\App\Services\AuditService::class)->log($auditAction, $leave, [
            'decision' => $decision,
            'remark' => $remark !== '' ? $remark : null,
        ]);

        return redirect()->back()->with('success', $decision === 'accepted'
            ? 'Withdrawal accepted. Leave cancelled and balance restored.'
            : 'Withdrawal rejected. Leave remains approved.');
    }

    public function updateStatus(Request $request, Leave $leave, LeaveLedgerService $ledger)
    {
        $reviewer = Auth::user();
        $companyId = $reviewer?->company_id;
        if ($companyId && $leave->company_id !== $companyId) {
            abort(403);
        }

        $this->authorize('approve', $leave);

        $validated = $request->validate([
            'status' => ['required', Rule::in(['approved', 'rejected'])],
            'remark' => ['nullable', 'string', 'max:1000'],
        ]);

        $previousStatus = $leave->status;

        $leave->update([
            'status' => $validated['status'],
            'remark' => trim((string) ($validated['remark'] ?? '')) !== '' ? $validated['remark'] : null,
            'is_paid' => $leave->is_paid || (bool) ($leave->leaveType?->is_paid ?? false),
        ]);

        if ($previousStatus === 'pending' && $validated['status'] === 'approved') {
            $ledger->consumePending($leave);
        } elseif ($previousStatus === 'pending' && $validated['status'] === 'rejected') {
            $ledger->releasePending($leave);
        } elseif ($previousStatus === 'approved' && $validated['status'] === 'rejected') {
            $ledger->reverseApproved($leave);
        }

        $leave->load(['user', 'leaveType']);
        $leave->user?->notify(new LeaveReviewedNotification($leave, $validated['status']));

        app(\App\Services\AuditService::class)->log('leave.'.$validated['status'], $leave, [
            'previous_status' => $previousStatus,
        ]);

        return redirect()->back()->with('success', 'Leave status updated successfully.');
    }

    public function dashboard(Request $request, LeaveLedgerService $ledger, LeaveDashboardStatsService $statsService)
    {
        $authUser = Auth::user();
        $companyId = $authUser?->company_id;
        $currentLeaveYear = $ledger->leaveYear();
        $year = (int) $request->integer('year', $currentLeaveYear);
        if ($year < 2000 || $year > 2100) {
            $year = $currentLeaveYear;
        }
        $visibleUserIds = $authUser?->visibleStaffUserIds() ?? [];

        $balances = $ledger->balancesForUser($authUser, $year);
        $allowAdvanceMonthly = $ledger->allowsAdvanceMonthly($companyId);
        $allowMonthlyOpeningOverride = $ledger->allowsMonthlyOpeningOverride($companyId);
        $latestMonthlyAccrualMonth = $ledger->latestMonthlyAccrualMonthForCompany($companyId, $year);
        $expectedMonth = now()->startOfMonth()->format('Y-m');
        $accrualScheduleWarning = null;
        if ($year === $currentLeaveYear) {
            if ($latestMonthlyAccrualMonth === null) {
                $accrualScheduleWarning = "Monthly accrual has not run yet for {$year}.";
            } elseif ($latestMonthlyAccrualMonth < $expectedMonth) {
                $accrualScheduleWarning = "Monthly accrual appears behind. Last credited month: {$latestMonthlyAccrualMonth}.";
            }
        }

        $leaveStats = $statsService->leaveStatsForUser($authUser, $year);
        $monthlyGeneration = $statsService->monthlyGeneration(
            $authUser,
            $year,
            $balances,
            $latestMonthlyAccrualMonth,
            $accrualScheduleWarning
        );
        $ruleSummaries = $statsService->ruleSummaries($authUser, $balances);

        $pendingQuery = Leave::with(['user', 'leaveType'])
            ->where('status', 'pending');
        if ($companyId) {
            $pendingQuery->where('company_id', $companyId);
        }
        if (! empty($visibleUserIds)) {
            $pendingQuery->whereIn('user_id', $visibleUserIds);
        }
        $pendingLeaves = $pendingQuery->orderByDesc('created_at')->limit(10)->get();

        $recentLeaves = Leave::with(['user', 'leaveType'])
            ->when($companyId, fn ($q) => $q->where('company_id', $companyId))
            ->where('user_id', $authUser->id)
            ->orderByDesc('created_at')
            ->limit(8)
            ->get();

        $teamBalances = [];
        if ($authUser?->isTenantManager()) {
            $teamUsers = User::query()
                ->forActiveDirectory()
                ->when($companyId, fn ($q) => $q->where('company_id', $companyId))
                ->when(! empty($visibleUserIds), fn ($q) => $q->whereIn('id', $visibleUserIds))
                ->where('id', '!=', $authUser->id)
                ->orderBy('name')
                ->limit(50)
                ->get();

            foreach ($teamUsers as $teamUser) {
                $teamBalances[] = [
                    'user' => $teamUser,
                    'balances' => $ledger->balancesForUser($teamUser, $year),
                ];
            }
        }

        $yearOptions = range($currentLeaveYear, $currentLeaveYear - 4);

        return view('leaves.dashboard', compact(
            'balances',
            'pendingLeaves',
            'recentLeaves',
            'teamBalances',
            'year',
            'yearOptions',
            'allowAdvanceMonthly',
            'allowMonthlyOpeningOverride',
            'latestMonthlyAccrualMonth',
            'accrualScheduleWarning',
            'leaveStats',
            'monthlyGeneration',
            'ruleSummaries'
        ));
    }

    public function balanceLookup(Request $request, LeaveLedgerService $ledger)
    {
        $companyId = Auth::user()?->company_id;
        $validated = $request->validate([
            'user_id' => ['required', 'integer'],
            'leave_type_id' => ['required', 'integer'],
        ]);

        $user = User::query()
            ->forActiveDirectory()
            ->when($companyId, fn ($q) => $q->where('company_id', $companyId))
            ->findOrFail($validated['user_id']);

        $leaveType = LeaveType::query()
            ->when($companyId, fn ($q) => $q->where('company_id', $companyId))
            ->findOrFail($validated['leave_type_id']);

        $available = $ledger->availableLeaveDays($user, $leaveType);
        $leaveType->loadMissing('rule');
        $accrualMode = $leaveType->rule?->accrual_mode ?? LeaveLedgerService::ACCRUAL_YEARLY;
        $earnedAsOfToday = $ledger->earnedLeaveDaysAsOf($user, $leaveType, now());
        $entitlement = $ledger->annualEntitlement($leaveType);

        return response()->json([
            'available' => $available === PHP_FLOAT_MAX ? null : round($available, 2),
            'is_unlimited' => $leaveType->is_unlimited,
            'is_paid' => (bool) $leaveType->is_paid,
            'accrual_mode' => $accrualMode,
            'earned_as_of_today' => $earnedAsOfToday === PHP_FLOAT_MAX ? null : round($earnedAsOfToday, 2),
            'annual_entitlement' => $entitlement === PHP_FLOAT_MAX ? null : round($entitlement, 2),
        ]);
    }

    public function leavePopup(Request $request, LeaveLedgerService $ledger)
    {
        $authUser = Auth::user();
        $companyId = $authUser?->company_id;

        $leaveId = $request->query('leave_id');
        $leave = Leave::with(['user', 'leaveType', 'documents'])
            ->when($companyId, fn ($q) => $q->where('company_id', $companyId))
            ->findOrFail($leaveId);

        $availableLeaves = $ledger->availableLeaveDays($leave->user, $leave->leaveType);
        if ($availableLeaves === PHP_FLOAT_MAX) {
            $availableLeaves = null;
        }

        $canApprove = $authUser?->can('approve', $leave) ?? false;
        $canWithdraw = $authUser?->can('withdraw', $leave) ?? false;
        $canReviewWithdraw = $canApprove && $leave->isWithdrawalPending();

        return view('leaves.leave-popup', compact('leave', 'availableLeaves', 'canApprove', 'canWithdraw', 'canReviewWithdraw'));
    }

    /**
     * Sidebar context for leave create/edit screens.
     *
     * @return array{sidebarBalances: array<int, array<string, mixed>>, recentLeaves: \Illuminate\Support\Collection, upcomingHolidays: \Illuminate\Support\Collection, balanceAsOf: string, sidebarSubjectName: ?string}
     */
    private function createSidebarData(?User $subjectUser, LeaveLedgerService $ledger): array
    {
        $authUser = Auth::user();
        $user = $subjectUser ?? $authUser;
        $companyId = $user?->company_id ?? $authUser?->company_id;
        $year = $ledger->leaveYear();

        $sidebarBalances = $user
            ? collect($ledger->balancesForUser($user, $year))->take(4)->values()->all()
            : [];

        $recentLeaves = Leave::with(['leaveType'])
            ->when($companyId, fn ($q) => $q->where('company_id', $companyId))
            ->when($user, fn ($q) => $q->where('user_id', $user->id))
            ->orderByDesc('created_at')
            ->limit(3)
            ->get();

        $upcomingHolidays = Holiday::query()
            ->when($companyId, fn ($q) => $q->where('company_id', $companyId))
            ->whereDate('date', '>=', now()->toDateString())
            ->orderBy('date')
            ->limit(5)
            ->get(['id', 'name', 'date']);

        return [
            'sidebarBalances' => $sidebarBalances,
            'recentLeaves' => $recentLeaves,
            'upcomingHolidays' => $upcomingHolidays,
            'balanceAsOf' => now()->format('d M Y'),
            'sidebarSubjectName' => $user?->name,
        ];
    }
}
