<?php

namespace App\Services\Dashboard;

use App\Models\Attendance;
use App\Models\Leave;
use App\Models\PayrollCycle;
use App\Models\User;
use App\Services\Finance\FinanceNavService;
use App\Services\Payroll\PayrollCycleService;
use Carbon\Carbon;
use Illuminate\Support\Collection;

class AdminDashboardService
{
    public function __construct(
        protected PayrollCycleService $payrollCycles,
        protected FinanceNavService $financeNav
    ) {}

    /**
     * @return array<string, mixed>
     */
    public function build(User $user, int $companyId, string $today): array
    {
        $now = Carbon::parse($today);
        $year = (int) $now->year;
        $month = (int) $now->month;

        $totalEmployees = User::query()
            ->where('company_id', $companyId)
            ->forActiveDirectory()
            ->count();

        $presentToday = (int) Attendance::query()
            ->where('company_id', $companyId)
            ->where('date', $today)
            ->whereNotNull('clock_in_date_time')
            ->distinct('user_id')
            ->count('user_id');

        $onLeaveTodayLeaves = Leave::query()
            ->with(['user:id,name,profile_photo'])
            ->where('company_id', $companyId)
            ->where('status', '!=', 'rejected')
            ->where('start_date', '<=', $today)
            ->where('end_date', '>=', $today)
            ->get()
            ->unique('user_id')
            ->filter(fn (Leave $leave) => $leave->user !== null)
            ->sortBy(fn (Leave $leave) => strtolower((string) $leave->user->name))
            ->values();

        $onLeaveToday = $onLeaveTodayLeaves->count();

        $onLeaveTodayRows = $onLeaveTodayLeaves->take(6)->map(function (Leave $leave) {
            return [
                'user' => $leave->user,
                'name' => (string) $leave->user->name,
            ];
        })->values()->all();

        $pendingLeaves = Leave::query()
            ->where('company_id', $companyId)
            ->where('status', 'pending')
            ->count();

        $pendingLeaveRows = Leave::query()
            ->with(['user', 'leaveType'])
            ->where('company_id', $companyId)
            ->where('status', 'pending')
            ->orderByDesc('created_at')
            ->limit(6)
            ->get();

        $newThisMonth = User::query()
            ->where('company_id', $companyId)
            ->forActiveDirectory()
            ->whereYear('joining_date', $year)
            ->whereMonth('joining_date', $month)
            ->count();

        $absentEstimate = max(0, $totalEmployees - $presentToday - $onLeaveToday);
        $attendanceRate = $totalEmployees > 0
            ? (int) round(($presentToday / $totalEmployees) * 100)
            : 0;

        $canViewPayroll = $user->hasPermission('payrolls_view');
        $payrollSnapshot = null;

        if ($canViewPayroll) {
            $cycle = $this->payrollCycles->getCycle($companyId, $year, $month);
            $payrollSnapshot = $this->payrollSnapshot($cycle, $year, $month);
        }

        $kpis = [
            [
                'key' => 'headcount',
                'title' => 'Active employees',
                'value' => $totalEmployees,
                'hint' => 'In company directory',
                'href' => route('employees.index'),
                'icon' => 'bi-people',
                'tone' => 'sky',
            ],
            [
                'key' => 'attendance',
                'title' => 'Present today',
                'value' => $presentToday,
                'hint' => $attendanceRate.'% attendance · ~'.$absentEstimate.' unmarked',
                'href' => route('attendance.index'),
                'icon' => 'bi-check-circle',
                'tone' => 'emerald',
            ],
            [
                'key' => 'leave',
                'title' => 'On leave today',
                'value' => $onLeaveToday,
                'hint' => $pendingLeaves.' pending approval'.($pendingLeaves === 1 ? '' : 's'),
                'href' => route('leaves.index'),
                'icon' => 'bi-calendar-x',
                'tone' => 'amber',
                'leave_rows' => $onLeaveTodayRows,
            ],
        ];

        if ($canViewPayroll && $payrollSnapshot) {
            $kpis[] = [
                'key' => 'payroll',
                'title' => 'Payroll · '.$now->format('M Y'),
                'value' => $payrollSnapshot['label'],
                'hint' => $payrollSnapshot['hint'],
                'href' => route('payroll.index', ['tab' => 'run', 'year' => $year, 'month' => $month]),
                'icon' => 'bi-cash-stack',
                'tone' => $payrollSnapshot['tone'],
            ];
        }

        return [
            'greeting' => $this->greeting($user),
            'zone' => $this->zoneLabel($user),
            'date_label' => $now->format('l, j F Y'),
            'kpis' => $kpis,
            'secondary_stats' => [
                ['label' => 'New joinees this month', 'value' => $newThisMonth],
                ['label' => 'Pending leave requests', 'value' => $pendingLeaves],
            ],
            'action_queue' => $this->actionQueue($user, $pendingLeaves, $pendingLeaveRows, $payrollSnapshot ?? []),
            'quick_actions' => $this->quickActions($user),
            'payroll_snapshot' => $payrollSnapshot,
        ];
    }

    protected function greeting(User $user): string
    {
        $hour = (int) now()->format('G');
        $name = explode(' ', trim((string) $user->name))[0] ?: 'there';

        $timeGreeting = match (true) {
            $hour < 12 => 'Good morning',
            $hour < 17 => 'Good afternoon',
            default => 'Good evening',
        };

        return $timeGreeting.', '.$name;
    }

    protected function zoneLabel(User $user): string
    {
        if ($user->isCompanyAccountAdmin()) {
            return 'Company overview';
        }

        return match ($user->role?->name) {
            'hr' => 'HR operations',
            'manager' => 'Team overview',
            'finance' => 'Finance & people',
            default => 'Admin overview',
        };
    }

    /**
     * @return array{label: string, hint: string, tone: string, status: ?string}
     */
    protected function payrollSnapshot(?PayrollCycle $cycle, int $year, int $month): array
    {
        if (! $cycle) {
            return [
                'label' => 'Not started',
                'hint' => 'Open run payroll to calculate this month',
                'tone' => 'slate',
                'status' => null,
            ];
        }

        $status = (string) $cycle->status;

        return match (true) {
            $cycle->isLocked() => [
                'label' => 'Locked',
                'hint' => 'Cycle finalized — no further edits',
                'tone' => 'slate',
                'status' => $status,
            ],
            $cycle->isCompleted() => [
                'label' => 'Completed',
                'hint' => 'Ready for payout or lock',
                'tone' => 'emerald',
                'status' => $status,
            ],
            $status === 'processing' => [
                'label' => 'Processing',
                'hint' => 'Calculation in progress',
                'tone' => 'sky',
                'status' => $status,
            ],
            default => [
                'label' => ucfirst($status ?: 'Draft'),
                'hint' => 'Review and calculate employee payslips',
                'tone' => 'amber',
                'status' => $status,
            ],
        };
    }

    /**
     * @param  Collection<int, Leave>  $pendingLeaveRows
     * @return list<array<string, mixed>>
     */
    protected function actionQueue(
        User $user,
        int $pendingLeaves,
        Collection $pendingLeaveRows,
        array $payrollSnapshot
    ): array {
        $items = [];

        if ($pendingLeaves > 0 && ($user->hasPermission('leaves_approve_reject') || $user->isTenantManager())) {
            $items[] = [
                'type' => 'leave',
                'title' => 'Leave approvals',
                'count' => $pendingLeaves,
                'href' => route('leaves.index', ['status' => 'pending']),
                'rows' => $pendingLeaveRows->map(fn (Leave $leave) => [
                    'id' => $leave->id,
                    'name' => $leave->user?->name ?? 'Employee',
                    'meta' => ($leave->leaveType?->name ?? 'Leave').' · '.$leave->start_date?->format('d M'),
                    'href' => route('leaves.index', ['status' => 'pending']),
                ])->values()->all(),
            ];
        }

        if ($user->hasPermission('payrolls_view')) {
            $payrollNeedsAction = ! in_array($payrollSnapshot['status'] ?? '', ['completed', 'locked'], true);
            if ($payrollNeedsAction) {
                $items[] = [
                    'type' => 'payroll',
                    'title' => 'Payroll this month',
                    'count' => 1,
                    'href' => route('payroll.index', ['tab' => 'run']),
                    'rows' => [[
                        'name' => $payrollSnapshot['label'],
                        'meta' => $payrollSnapshot['hint'],
                        'href' => route('payroll.index', ['tab' => 'run']),
                    ]],
                ];
            }
        }

        if ($this->financeNav->canAccessModule($user) && ($user->hasPermission('finance_team_view') || $this->financeNav->canViewCompanyExpenses($user))) {
            $pendingExpenses = \App\Models\Expense::query()
                ->where('company_id', $user->company_id)
                ->where('status', 'pending')
                ->count();

            if ($pendingExpenses > 0) {
                $scope = $this->financeNav->canViewCompanyExpenses($user) ? 'company' : 'team';
                $items[] = [
                    'type' => 'expense',
                    'title' => 'Expense claims',
                    'count' => $pendingExpenses,
                    'href' => route('expenses.index', ['scope' => $scope, 'status' => 'pending']),
                    'rows' => [],
                ];
            }
        }

        return $items;
    }

    /**
     * @return list<array{label: string, href: string, icon: string, primary: bool, tone?: string, icon_color?: string}>
     */
    protected function quickActions(User $user): array
    {
        $actions = [];

        if ($user->hasPermission('users_create')) {
            $actions[] = [
                'label' => 'Add employee',
                'href' => route('employees.create'),
                'icon' => 'bi-person-plus',
                'tone' => 'sky',
                'primary' => true,
            ];
        }

        if ($user->hasPermission('leaves_approve_reject') || $user->isTenantManager()) {
            $actions[] = [
                'label' => 'Review leaves',
                'href' => route('leaves.index', ['status' => 'pending']),
                'icon' => 'bi-calendar-check',
                'tone' => 'rose',
                'primary' => false,
            ];
        }

        if ($user->hasPermission('attendances_view') || $user->isTenantManager()) {
            $actions[] = [
                'label' => 'Attendance',
                'href' => route('attendance.index'),
                'icon' => 'bi-clock-history',
                'tone' => 'violet',
                'primary' => false,
            ];
        }

        if ($user->hasPermission('payrolls_view')) {
            $actions[] = [
                'label' => 'Run payroll',
                'href' => route('payroll.index', ['tab' => 'run']),
                'icon' => 'bi-calculator',
                'tone' => 'emerald',
                'primary' => false,
            ];
        }

        if ($this->financeNav->hasTreasuryAccess($user)) {
            $actions[] = [
                'label' => 'Finance',
                'href' => $this->financeNav->homeUrl($user),
                'icon' => 'bi-wallet2',
                'tone' => 'amber',
                'primary' => false,
            ];
        } elseif ($this->financeNav->canAccessModule($user)) {
            $actions[] = [
                'label' => 'My finance',
                'href' => $this->financeNav->homeUrl($user),
                'icon' => 'bi-receipt',
                'tone' => 'teal',
                'primary' => false,
            ];
        }

        return $actions;
    }
}
