<?php

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Models\Attendance;
use App\Models\AttendanceRegularization;
use App\Models\Department;
use App\Models\EmployeePayroll;
use App\Models\EmployeePayrollComponent;
use App\Models\Holiday;
use App\Models\Leave;
use App\Models\LeaveType;
use App\Models\PayrollCycle;
use App\Models\Resignation;
use App\Models\User;
use App\Services\Documents\EmployeeDocumentComplianceService;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

class DashboardController extends Controller
{
    public function __construct(
        protected EmployeeDocumentComplianceService $documentCompliance
    ) {}

    /**
     * @param  array<int>  $visibleIds
     * @return array<string, mixed>
     */
    private function buildMetricsPayload(
        int $companyId,
        array $visibleIds,
        string $today,
        int $year,
        int $month,
        Carbon $now,
        bool $includePayrollSignals
    ): array {
        $idList = array_values(array_unique(array_map('intval', $visibleIds)));

        $leaveUserIdsToday = Leave::query()
            ->where('company_id', $companyId)
            ->whereIn('status', Leave::approvedLikeStatuses())
            ->whereDate('start_date', '<=', $today)
            ->whereDate('end_date', '>=', $today)
            ->whereIn('user_id', $idList)
            ->pluck('user_id')
            ->unique()
            ->all();

        $presentToday = (int) Attendance::query()
            ->where('company_id', $companyId)
            ->whereDate('date', $today)
            ->whereIn('user_id', $idList)
            ->whereNotNull('clock_in_date_time')
            ->whereNotIn('user_id', $leaveUserIdsToday)
            ->selectRaw('COUNT(DISTINCT user_id) as c')
            ->value('c');

        $onLeaveToday = count(array_unique($leaveUserIdsToday));

        $totalStaff = (int) User::query()
            ->where('company_id', $companyId)
            ->forActiveDirectory()
            ->whereIn('id', $idList)
            ->count();

        $absentToday = max(0, $totalStaff - $presentToday - $onLeaveToday);

        $lateToday = (int) Attendance::query()
            ->where('company_id', $companyId)
            ->whereDate('date', $today)
            ->whereIn('user_id', $idList)
            ->where('is_late', true)
            ->selectRaw('COUNT(DISTINCT user_id) as c')
            ->value('c');

        $newJoinersMonth = (int) User::query()
            ->where('company_id', $companyId)
            ->forActiveDirectory()
            ->whereIn('id', $idList)
            ->whereYear('joining_date', $year)
            ->whereMonth('joining_date', $month)
            ->whereNotNull('joining_date')
            ->count();

        $exitsMtd = (int) Resignation::query()
            ->where('company_id', $companyId)
            ->whereIn('user_id', $idList)
            ->whereYear('resignation_date', $year)
            ->whereMonth('resignation_date', $month)
            ->count();

        $attritionRate = $totalStaff > 0
            ? round(($exitsMtd / $totalStaff) * 100, 2)
            : 0.0;

        $attendanceTodaySummary = [
            'present' => $presentToday,
            'absent' => $absentToday,
            'on_leave' => $onLeaveToday,
            'late' => $lateToday,
        ];

        $weeklyTrend = $this->weeklyPresentTrend($companyId, $idList, $today);

        $leaveTypeDistribution = Leave::query()
            ->join('leave_types', 'leaves.leave_type_id', '=', 'leave_types.id')
            ->where('leaves.company_id', $companyId)
            ->where('leaves.status', 'approved')
            ->whereIn('leaves.user_id', $idList)
            ->where('leaves.start_date', '>=', $now->copy()->subMonths(6)->toDateString())
            ->groupBy('leave_types.id', 'leave_types.name')
            ->selectRaw('leave_types.name as name, SUM(leaves.total_days) as days')
            ->orderByDesc('days')
            ->limit(8)
            ->get();

        $pendingLeaves = Leave::query()
            ->with(['user:id,name,department_id', 'leaveType:id,name'])
            ->where('company_id', $companyId)
            ->where('status', 'pending')
            ->whereIn('user_id', $idList)
            ->orderByDesc('created_at')
            ->limit(8)
            ->get();

        $leaveBalanceAlerts = $this->leaveBalanceAlerts($companyId, $idList);

        $payrollBlock = $includePayrollSignals
            ? $this->payrollComplianceBlock($companyId, $year, $month, $idList)
            : [
                'status_label' => 'restricted',
                'employee_count' => 0,
                'pending_count' => 0,
                'v2_cycle_status' => null,
                'total_disbursed' => 0.0,
                'pf_total' => 0.0,
                'esi_total' => 0.0,
                'alerts' => [],
            ];

        $lifecycle = $this->lifecycleBlock($companyId, $idList, $year, $month, $now);

        $departmentPerformance = $this->departmentPerformance($companyId, $idList, $today, $includePayrollSignals);

        $calendarEvents = $this->calendarEvents($companyId, $idList, $now);

        $hiringVsExits = $this->hiringVsExitsSeries($companyId, $idList, $now);

        $aiInsights = $this->buildAiInsights(
            $absentToday,
            $totalStaff,
            $attritionRate,
            $lateToday,
            $payrollBlock,
            $includePayrollSignals
        );

        return [
            'kpis' => [
                'total_employees' => $totalStaff,
                'present_today' => $presentToday,
                'absent_today' => $absentToday,
                'on_leave_today' => $onLeaveToday,
                'new_joiners_month' => $newJoinersMonth,
                'attrition_rate' => $attritionRate,
            ],
            'kpiMeta' => [
                'absent' => $absentToday > ($totalStaff * 0.15) ? 'critical' : ($absentToday > ($totalStaff * 0.08) ? 'warning' : 'positive'),
                'attrition' => $attritionRate > 5 ? 'critical' : ($attritionRate > 2 ? 'warning' : 'positive'),
                'late' => $lateToday > ($totalStaff * 0.1) ? 'warning' : 'positive',
            ],
            'attendanceTodaySummary' => $attendanceTodaySummary,
            'chartWeeklyAttendance' => $weeklyTrend,
            'leaveTypeDistribution' => $leaveTypeDistribution,
            'pendingLeaves' => $pendingLeaves,
            'leaveBalanceAlerts' => $leaveBalanceAlerts,
            'payrollBlock' => $payrollBlock,
            'lifecycle' => $lifecycle,
            'departmentPerformance' => $departmentPerformance,
            'calendarEvents' => $calendarEvents,
            'chartHiringVsExits' => $hiringVsExits,
            'aiInsights' => $aiInsights,
        ];
    }

    /**
     * Rebuild lightweight task lists per request (manager visibility for regularizations).
     *
     * @param  array<int>  $visibleIds
     * @return array<string, mixed>
     */
    private function buildTasksOutsideCache(int $companyId, array $visibleIds, $actor): array
    {
        $idList = array_values(array_unique(array_map('intval', $visibleIds)));
        $pendingLeaveCount = Leave::query()
            ->where('company_id', $companyId)
            ->where('status', 'pending')
            ->whereIn('user_id', $idList)
            ->count();

        $pendingRegQuery = AttendanceRegularization::query()
            ->where('company_id', $companyId)
            ->where('status', AttendanceRegularization::STATUS_PENDING)
            ->whereIn('user_id', $idList);

        $pendingRegsAll = (clone $pendingRegQuery)
            ->with(['user'])
            ->orderByDesc('date')
            ->get();

        $pendingRegsApprovable = $pendingRegsAll->filter(
            fn (AttendanceRegularization $regularization) => $actor->canApproveRegularization($regularization)
        )->values();

        $pendingRegCount = $pendingRegsApprovable->count();

        $pendingRegsPreview = $pendingRegsApprovable->take(5);

        $probationSoon = $this->probationEndingSoon($companyId, $idList, Carbon::now());

        return [
            'pending_leave_count' => $pendingLeaveCount,
            'pending_regularization_count' => $pendingRegCount,
            'pending_regularizations' => $pendingRegsPreview,
            'probation_soon' => $probationSoon,
            'documentComplianceGaps' => $this->documentCompliance->gapsForUsers($companyId, $idList),
        ];
    }

    public function index(Request $request)
    {
        $user = $request->user();
        $companyId = $user?->company_id;

        $roleName = $user?->role?->name ?? 'employee';
        $isAccountCompanyAdmin = $user?->isCompanyAccountAdmin() ?? false;
        $isAdmin = $roleName === 'admin' || $isAccountCompanyAdmin;
        $isManager = in_array($roleName, ['admin', 'manager'], true) || $isAccountCompanyAdmin;
        $isHrStyle = $isManager;
        $canViewPayrollAnalytics = (bool) ($user?->hasPermission('payrolls_view'));

        if (! $companyId) {
            return view('employees.dashboard', $this->emptyPayload($roleName, $isAdmin, $isHrStyle));
        }

        $visibleIds = $user->visibleStaffUserIds();
        if (empty($visibleIds)) {
            $visibleIds = [$user->id];
        }

        $today = Carbon::today()->toDateString();
        $now = Carbon::now();
        $year = (int) $now->year;
        $month = (int) $now->month;

        $cacheKey = sprintf(
            'people_dashboard_v2:%d:%s:%s:%s:%d',
            (int) $companyId,
            $today,
            $roleName,
            hash('xxh128', implode(',', $visibleIds)),
            $canViewPayrollAnalytics ? 1 : 0
        );

        $cached = Cache::remember($cacheKey, now()->addMinutes(5), function () use (
            $companyId,
            $visibleIds,
            $today,
            $year,
            $month,
            $now,
            $canViewPayrollAnalytics
        ) {
            return $this->buildMetricsPayload(
                (int) $companyId,
                $visibleIds,
                $today,
                $year,
                $month,
                $now,
                $canViewPayrollAnalytics
            );
        });

        $tasks = $this->buildTasksOutsideCache((int) $companyId, $visibleIds, $user);

        return view('employees.dashboard', array_merge($cached, $tasks, [
            'pageRoleName' => $roleName,
            'isAdmin' => $isAdmin,
            'isHrStyle' => $isHrStyle,
            'canViewPayrollAnalytics' => $canViewPayrollAnalytics,
            'clientIp' => $request->ip(),
        ]));
    }

    private function emptyPayload(string $roleName, bool $isAdmin, bool $isHrStyle): array
    {
        return [
            'kpis' => [
                'total_employees' => 0,
                'present_today' => 0,
                'absent_today' => 0,
                'on_leave_today' => 0,
                'new_joiners_month' => 0,
                'attrition_rate' => 0,
            ],
            'kpiMeta' => [],
            'attendanceTodaySummary' => ['present' => 0, 'absent' => 0, 'on_leave' => 0, 'late' => 0],
            'chartWeeklyAttendance' => ['labels' => [], 'dates' => [], 'present' => []],
            'leaveTypeDistribution' => collect(),
            'pendingLeaves' => collect(),
            'leaveBalanceAlerts' => collect(),
            'payrollBlock' => [
                'status_label' => '—',
                'employee_count' => 0,
                'pending_count' => 0,
                'v2_cycle_status' => null,
                'total_disbursed' => 0.0,
                'pf_total' => 0.0,
                'esi_total' => 0.0,
                'alerts' => [],
            ],
            'lifecycle' => [
                'new_joiners_mtd' => 0,
                'resignations_mtd' => 0,
                'confirmations_due' => 0,
            ],
            'departmentPerformance' => collect(),
            'calendarEvents' => ['holidays' => collect(), 'birthdays' => collect(), 'anniversaries' => collect()],
            'chartHiringVsExits' => ['labels' => [], 'hires' => [], 'exits' => []],
            'documentComplianceGaps' => collect(),
            'aiInsights' => [],
            'pending_leave_count' => 0,
            'pending_regularization_count' => 0,
            'pending_regularizations' => collect(),
            'probation_soon' => collect(),
            'pageRoleName' => $roleName,
            'isAdmin' => $isAdmin,
            'isHrStyle' => $isHrStyle,
            'canViewPayrollAnalytics' => false,
            'clientIp' => request()->ip(),
        ];
    }

    /**
     * @param  array<int>  $visibleIds
     * @return array{labels: array<int, string>, dates: array<int, string>, present: array<int, int>}
     */
    private function weeklyPresentTrend(int $companyId, array $visibleIds, string $today): array
    {
        $labels = [];
        $dates = [];
        $data = [];
        for ($i = 6; $i >= 0; $i--) {
            $day = Carbon::parse($today)->subDays($i);
            $date = $day->toDateString();
            $labels[] = $day->format('D, M j');
            $dates[] = $date;

            $leaveIds = Leave::query()
                ->where('company_id', $companyId)
                ->whereIn('status', Leave::approvedLikeStatuses())
                ->whereDate('start_date', '<=', $date)
                ->whereDate('end_date', '>=', $date)
                ->whereIn('user_id', $visibleIds)
                ->pluck('user_id')
                ->unique()
                ->all();

            $query = Attendance::query()
                ->where('company_id', $companyId)
                ->whereDate('date', $date)
                ->whereIn('user_id', $visibleIds)
                ->whereNotNull('clock_in_date_time');

            if ($leaveIds !== []) {
                $query->whereNotIn('user_id', $leaveIds);
            }

            $c = (int) $query
                ->selectRaw('COUNT(DISTINCT user_id) as c')
                ->value('c');

            $data[] = $c;
        }

        return ['labels' => $labels, 'dates' => $dates, 'present' => $data];
    }

    /**
     * @param  array<int>  $visibleIds
     * @return Collection<int, object>
     */
    private function leaveBalanceAlerts(int $companyId, array $visibleIds): Collection
    {
        $types = LeaveType::query()
            ->where('company_id', $companyId)
            ->where('is_unlimited', false)
            ->get(['id', 'name', 'total_leaves', 'leave_count']);

        $alerts = collect();
        foreach ($types as $lt) {
            $allocated = (float) ($lt->leave_count ?? $lt->total_leaves ?? 0);
            if ($allocated <= 0) {
                continue;
            }
            $used = (float) Leave::query()
                ->where('company_id', $companyId)
                ->where('leave_type_id', $lt->id)
                ->whereIn('status', Leave::approvedLikeStatuses())
                ->whereIn('user_id', $visibleIds)
                ->whereYear('start_date', Carbon::now()->year)
                ->sum('total_days');

            $pct = $allocated > 0 ? round(($used / max($allocated * max(1, count($visibleIds)), 0.0001)) * 100, 1) : 0;
            if ($used > 0 && $pct > 70) {
                $alerts->push((object) [
                    'leave_type' => $lt->name,
                    'used' => $used,
                    'allocated_hint' => $allocated,
                    'pct' => min(100, $pct),
                ]);
            }
        }

        return $alerts->take(6);
    }

    /**
     * @param  array<int>  $visibleIds
     * @return array<string, mixed>
     */
    private function payrollComplianceBlock(int $companyId, int $year, int $month, array $visibleIds): array
    {
        $cycle = PayrollCycle::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->where('year', $year)
            ->where('month', $month)
            ->first();

        $employeeCount = 0;
        $netTotal = 0.0;
        $pendingCount = 0;

        if ($cycle) {
            $rows = EmployeePayroll::withoutGlobalScopes()
                ->where('company_id', $companyId)
                ->where('payroll_cycle_id', $cycle->id)
                ->get();
            $employeeCount = $rows->count();
            $netTotal = (float) $rows->sum('net_monthly');
            $pendingCount = $rows->filter(fn ($ep) => ! in_array($cycle->status, ['completed', 'locked'], true))->count();
        }

        $v2EmployeePayrollIds = $cycle
            ? EmployeePayroll::withoutGlobalScopes()
                ->where('company_id', $companyId)
                ->where('payroll_cycle_id', $cycle->id)
                ->pluck('id')
                ->all()
            : [];

        $pfTotal = 0.0;
        $esiTotal = 0.0;
        if (! empty($v2EmployeePayrollIds)) {
            $pfTotal = (float) EmployeePayrollComponent::withoutGlobalScopes()
                ->where('company_id', $companyId)
                ->whereIn('employee_payroll_id', $v2EmployeePayrollIds)
                ->where('category', 'employer_contribution')
                ->where(function ($q) {
                    $q->whereIn('component_code', ['PF_EMPR', 'PF_EMP'])
                        ->orWhereRaw('LOWER(name) LIKE ?', ['%pf%employer%'])
                        ->orWhereRaw('LOWER(name) LIKE ?', ['%provident%']);
                })
                ->sum('amount');

            $esiTotal = (float) EmployeePayrollComponent::withoutGlobalScopes()
                ->where('company_id', $companyId)
                ->whereIn('employee_payroll_id', $v2EmployeePayrollIds)
                ->where('category', 'employer_contribution')
                ->where(function ($q) {
                    $q->whereIn('component_code', ['ESI_EMPR', 'ESI_EMP'])
                        ->orWhereRaw('LOWER(name) LIKE ?', ['%esi%employer%']);
                })
                ->sum('amount');
        }

        $alerts = [];
        if (! $cycle || $employeeCount === 0) {
            $alerts[] = [
                'type' => 'warning',
                'message' => 'Payroll has not been generated for '.Carbon::create($year, $month)->format('F Y').'.',
            ];
        } elseif (! in_array($cycle->status, ['completed', 'locked'], true)) {
            $alerts[] = [
                'type' => 'warning',
                'message' => 'Payroll cycle for this month is not completed yet.',
            ];
        }

        $alerts[] = [
            'type' => 'info',
            'message' => 'Review PF / ESI remittance deadlines in compliance calendar (15th / as per state rules).',
        ];

        $statusLabel = 'pending';
        if ($cycle && in_array($cycle->status, ['completed', 'locked'], true)) {
            $statusLabel = 'generated';
        } elseif ($employeeCount > 0) {
            $statusLabel = 'partial';
        }

        return [
            'status_label' => $statusLabel,
            'employee_count' => $employeeCount,
            'pending_count' => $pendingCount,
            'v2_cycle_status' => $cycle?->status,
            'total_disbursed' => $netTotal,
            'pf_total' => round($pfTotal, 2),
            'esi_total' => round($esiTotal, 2),
            'alerts' => $alerts,
        ];
    }

    /**
     * @param  array<int>  $visibleIds
     * @return array<string, int|float>
     */
    private function lifecycleBlock(int $companyId, array $visibleIds, int $year, int $month, Carbon $now): array
    {
        $newJoiners = (int) User::query()
            ->where('company_id', $companyId)
            ->forActiveDirectory()
            ->whereIn('id', $visibleIds)
            ->whereYear('joining_date', $year)
            ->whereMonth('joining_date', $month)
            ->count();

        $resignations = (int) Resignation::query()
            ->where('company_id', $companyId)
            ->whereIn('user_id', $visibleIds)
            ->whereYear('resignation_date', $year)
            ->whereMonth('resignation_date', $month)
            ->count();

        $confirmationsDue = (int) User::query()
            ->where('company_id', $companyId)
            ->forActiveDirectory()
            ->whereIn('id', $visibleIds)
            ->whereNotNull('joining_date')
            ->whereRaw('DATE_ADD(joining_date, INTERVAL 1 YEAR) BETWEEN ? AND ?', [
                $now->copy()->startOfMonth()->toDateString(),
                $now->copy()->endOfMonth()->toDateString(),
            ])
            ->count();

        return [
            'new_joiners_mtd' => $newJoiners,
            'resignations_mtd' => $resignations,
            'confirmations_due' => $confirmationsDue,
        ];
    }

    /**
     * @param  array<int>  $visibleIds
     */
    private function departmentPerformance(int $companyId, array $visibleIds, string $today, bool $includePayrollSignals): Collection
    {
        $start = Carbon::parse($today)->subDays(6)->toDateString();

        $rows = Department::query()
            ->where('company_id', $companyId)
            ->withCount([
                'users as staff_count' => fn ($q) => $q->forActiveDirectory()->whereIn('id', $visibleIds),
            ])
            ->orderByDesc('staff_count')
            ->limit(12)
            ->get();

        $out = collect();
        foreach ($rows as $dept) {
            $deptUserIds = User::query()
                ->where('company_id', $companyId)
                ->where('department_id', $dept->id)
                ->forActiveDirectory()
                ->whereIn('id', $visibleIds)
                ->pluck('id')
                ->all();

            if (empty($deptUserIds)) {
                continue;
            }

            $presentCnt = (int) Attendance::query()
                ->where('company_id', $companyId)
                ->whereBetween('date', [$start, $today])
                ->whereIn('user_id', $deptUserIds)
                ->whereNotNull('clock_in_date_time')
                ->selectRaw('COUNT(DISTINCT CONCAT(user_id, "-", date)) as c')
                ->value('c');

            $denom = max(1, count($deptUserIds) * 7);
            $attendancePct = round(min(100, ($presentCnt / $denom) * 100), 1);

            $avgSalary = null;
            if ($includePayrollSignals) {
                $latestRevisionSub = DB::table('salary_revisions')
                    ->select('user_id', DB::raw('MAX(effective_date) as ed'))
                    ->where('company_id', $companyId)
                    ->whereIn('user_id', $deptUserIds)
                    ->groupBy('user_id');

                $avgSalary = (float) DB::table('salary_revisions as sr')
                    ->joinSub($latestRevisionSub, 'm', function ($join) {
                        $join->on('sr.user_id', '=', 'm.user_id')
                            ->on('sr.effective_date', '=', 'm.ed');
                    })
                    ->where('sr.company_id', $companyId)
                    ->whereIn('sr.user_id', $deptUserIds)
                    ->avg(DB::raw('sr.ctc_annual / 12'));
            }

            $out->push([
                'name' => $dept->name ?: 'Unassigned',
                'headcount' => (int) $dept->staff_count,
                'attendance_pct' => $attendancePct,
                'avg_salary' => $avgSalary !== null ? round((float) $avgSalary, 2) : null,
            ]);
        }

        return $out;
    }

    /**
     * @param  array<int>  $visibleIds
     */
    private function calendarEvents(int $companyId, array $visibleIds, Carbon $now): array
    {
        $holidays = Holiday::query()
            ->where('company_id', $companyId)
            ->whereDate('date', '>=', $now->toDateString())
            ->orderBy('date')
            ->limit(8)
            ->get();

        $birthdays = User::query()
            ->where('company_id', $companyId)
            ->forActiveDirectory()
            ->whereIn('id', $visibleIds)
            ->whereNotNull('dob')
            ->whereRaw('DATE_FORMAT(dob, "%m-%d") >= ?', [$now->format('m-d')])
            ->orderByRaw('DATE_FORMAT(dob, "%m-%d")')
            ->limit(8)
            ->get(['id', 'name', 'dob']);

        $anniversaries = User::query()
            ->where('company_id', $companyId)
            ->forActiveDirectory()
            ->whereIn('id', $visibleIds)
            ->whereNotNull('joining_date')
            ->whereRaw('DATE_FORMAT(joining_date, "%m-%d") >= ?', [$now->format('m-d')])
            ->orderByRaw('DATE_FORMAT(joining_date, "%m-%d")')
            ->limit(8)
            ->get(['id', 'name', 'joining_date']);

        return compact('holidays', 'birthdays', 'anniversaries');
    }

    /**
     * @param  array<int>  $visibleIds
     * @return array{labels: array, hires: array, exits: array}
     */
    private function hiringVsExitsSeries(int $companyId, array $visibleIds, Carbon $now): array
    {
        $labels = [];
        $hires = [];
        $exits = [];
        for ($i = 5; $i >= 0; $i--) {
            $d = $now->copy()->subMonths($i);
            $labels[] = $d->format('M Y');
            $hires[] = (int) User::query()
                ->where('company_id', $companyId)
                ->forActiveDirectory()
                ->whereIn('id', $visibleIds)
                ->whereYear('joining_date', $d->year)
                ->whereMonth('joining_date', $d->month)
                ->count();
            $exits[] = (int) Resignation::query()
                ->where('company_id', $companyId)
                ->whereIn('user_id', $visibleIds)
                ->whereYear('resignation_date', $d->year)
                ->whereMonth('resignation_date', $d->month)
                ->count();
        }

        return ['labels' => $labels, 'hires' => $hires, 'exits' => $exits];
    }

    /**
     * @param  array<int>  $visibleIds
     */
    private function probationEndingSoon(int $companyId, array $visibleIds, Carbon $now): Collection
    {
        $start = $now->copy()->addDay()->toDateString();
        $end = $now->copy()->addDays(30)->toDateString();

        return User::query()
            ->where('company_id', $companyId)
            ->forActiveDirectory()
            ->whereIn('id', $visibleIds)
            ->whereNotNull('joining_date')
            ->whereRaw('DATE_ADD(joining_date, INTERVAL 6 MONTH) BETWEEN ? AND ?', [$start, $end])
            ->orderBy('joining_date')
            ->limit(8)
            ->get(['id', 'name', 'joining_date']);
    }

    /**
     * @param  array<string, mixed>  $payrollBlock
     * @return array<int, array{type: string, message: string}>
     */
    private function buildAiInsights(
        int $absentToday,
        int $totalStaff,
        float $attritionRate,
        int $lateToday,
        array $payrollBlock,
        bool $includePayrollSignals
    ): array {
        $insights = [];
        if ($totalStaff > 0 && ($absentToday / $totalStaff) > 0.12) {
            $insights[] = ['type' => 'danger', 'title' => 'Absenteeism spike', 'message' => 'Today’s absent rate is elevated vs team size. Review shift coverage and unplanned leave.'];
        }
        if ($attritionRate > 3) {
            $insights[] = ['type' => 'warning', 'title' => 'Attrition signal', 'message' => 'MTD exits vs headcount suggests monitoring engagement and replacement planning.'];
        }
        if ($lateToday > max(3, (int) floor($totalStaff * 0.05))) {
            $insights[] = ['type' => 'warning', 'title' => 'Late arrivals', 'message' => 'Late check-ins are above typical levels; consider shift communication or transport issues.'];
        }
        if ($includePayrollSignals && (($payrollBlock['pending_count'] ?? 0) > 0 || ($payrollBlock['status_label'] ?? '') === 'pending')) {
            $insights[] = ['type' => 'info', 'title' => 'Payroll throughput', 'message' => 'Ensure payroll is generated and paid on time to avoid statutory and employee satisfaction risk.'];
        }

        if (empty($insights)) {
            $insights[] = ['type' => 'success', 'title' => 'Stable operations', 'message' => 'Key workforce signals are within normal range for today’s snapshot.'];
        }

        return $insights;
    }
}
