<?php

namespace App\Livewire;

use App\Domain\Attendance\Enums\AttendanceStatus;
use App\Domain\Attendance\Models\AttendanceRecord;
use App\Domain\Document\Enums\DocumentStatus;
use App\Domain\Document\Enums\DocumentType;
use App\Domain\Document\Models\Document;
use App\Domain\Financial\Enums\InvoiceStatus;
use App\Domain\Financial\Models\Expense;
use App\Domain\Financial\Models\Invoice;
use App\Domain\Financial\Models\Payment;
use App\Domain\HR\Enums\PayslipStatus;
use App\Domain\HR\Models\Payslip;
use App\Domain\Inventory\Models\Product;
use App\Domain\Participant\Models\Participant;
use App\Domain\Shared\Traits\UsesBranchScope;
use App\Domain\Training\Models\TrainingSession;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('لوحة التحكم')]
class Dashboard extends Component
{
    use UsesBranchScope;

    public function mount(): void
    {
        $user = auth()->user();
        $roleSlug = $user->primaryRole?->slug;

        // Checked before the role map so someone viewing every branch is never
        // dropped into a branch-scoped dashboard showing one branch's numbers.
        $branchContext = app(\App\Domain\Shared\Context\BranchContext::class);

        if ($branchContext->isLocked()) {
            $this->redirect(route($branchContext->redirectRouteName()));
            return;
        }

        // Redirect non-management roles to their dedicated dashboards
        $redirectMap = [
            'trainer' => 'trainer.dashboard',
            'head_trainer' => 'trainer.dashboard',
            'receptionist' => 'receptionist.dashboard',
            'parent' => 'guardian.dashboard',
        ];

        if (isset($redirectMap[$roleSlug])) {
            $this->redirect(route($redirectMap[$roleSlug]));
            return;
        }

        $this->authorize('dashboard.view');
    }

    public function render()
    {
        $today = now()->toDateString();
        $now = now();
        $branchId = $this->getActiveBranchId();

        // --- Row 1: Today's Overview (4 stat cards) ---
        $sessionsToday = TrainingSession::where('session_date', $today)
            ->whereIn('status', ['scheduled', 'in_progress'])
            ->when($branchId, fn ($q) => $q->whereHas('group', fn ($g) => $g->where('branch_id', $branchId)))
            ->count();

        $trainersPresent = AttendanceRecord::whereHas('session', function ($q) use ($today, $branchId) {
            $q->where('session_date', $today)
                ->when($branchId, fn ($s) => $s->whereHas('group', fn ($g) => $g->where('branch_id', $branchId)));
        })
            ->where('subject_type', \App\Models\User::class)
            ->whereIn('status', [AttendanceStatus::Present, AttendanceStatus::Late])
            ->count();

        $paymentsToday = Payment::where('direction', 'inbound')->where('status', 'confirmed')
            ->whereDate('created_at', $today)
            ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
            ->sum('amount');

        $expensesToday = Expense::whereDate('expense_date', $today)
            ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
            ->sum('amount');

        $expensesThisMonth = Expense::whereBetween('expense_date', [now()->startOfMonth(), now()->endOfMonth()])
            ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
            ->sum('amount');

        $cashExpensesThisMonth = Expense::whereBetween('expense_date', [now()->startOfMonth(), now()->endOfMonth()])
            ->where('payment_method', 'cash')
            ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
            ->sum('amount');

        $cashCollectionsThisMonth = Payment::where('direction', 'inbound')->where('status', 'confirmed')
            ->where('method', 'cash')
            ->whereBetween('created_at', [now()->startOfMonth(), now()->endOfMonth()])
            ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
            ->sum('amount');

        $expectedCashOnHand = $cashCollectionsThisMonth - $cashExpensesThisMonth;

        $activeParticipants = Participant::where('status', 'active')
            ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
            ->count();

        // --- Row 2: Needs Attention ---
        $overdueInvoicesCount = Invoice::where('status', InvoiceStatus::Overdue)
            ->when($branchId, fn ($q) => $q->whereHasMorph('billable', [Participant::class], fn ($p) => $p->where('branch_id', $branchId)))
            ->count();

        $pendingPayslips = Payslip::whereIn('status', [PayslipStatus::Draft, PayslipStatus::PendingApproval])
            ->when($branchId, fn ($q) => $q->whereHas('trainer.employee', fn ($e) => $e->forBranch($branchId)))
            ->count();

        $pendingDocuments = Document::where('status', DocumentStatus::Pending)
            ->when($branchId, fn ($q) => $q->whereHasMorph('documentable', [Participant::class], fn ($p) => $p->where('branch_id', $branchId)))
            ->count();

        $lowStockItems = Product::where('track_inventory', true)
            ->where('is_active', true)
            ->whereNotNull('min_stock_level')
            ->where('min_stock_level', '>', 0)
            ->when($branchId, fn ($q) => $q->where(fn ($b) => $b->whereNull('branch_id')->orWhere('branch_id', $branchId)))
            ->whereHas('inventoryLevels', function ($q) use ($branchId) {
                $q->whereRaw('quantity_on_hand <= (SELECT min_stock_level FROM products WHERE products.id = inventory_levels.product_id)')
                    ->when($branchId, fn ($l) => $l->where('branch_id', $branchId));
            })
            ->count();

        $expiringMedicalCerts = Document::where('document_type', DocumentType::MedicalCertificate)
            ->where('status', DocumentStatus::Approved)
            ->whereNotNull('expires_at')
            ->where('expires_at', '<=', now()->addDays(7))
            ->where('expires_at', '>=', $today)
            ->when($branchId, fn ($q) => $q->whereHasMorph('documentable', [Participant::class], fn ($p) => $p->where('branch_id', $branchId)))
            ->count();

        // Sessions that ended but attendance not taken
        $endedSessionIds = TrainingSession::where('session_date', $today)
            ->where('end_time', '<', $now->format('H:i:s'))
            ->whereIn('status', ['scheduled', 'in_progress', 'completed'])
            ->when($branchId, fn ($q) => $q->whereHas('group', fn ($g) => $g->where('branch_id', $branchId)))
            ->pluck('id');

        $attendanceNotTaken = 0;
        if ($endedSessionIds->isNotEmpty()) {
            $attendanceNotTaken = $endedSessionIds->count() - TrainingSession::whereIn('id', $endedSessionIds)
                ->whereHas('attendanceRecords', fn ($q) => $q->where('status', '!=', AttendanceStatus::Expected))
                ->count();
            $attendanceNotTaken = max(0, $attendanceNotTaken);
        }

        // --- Row 3 Left: Today's Schedule ---
        $todaySchedule = TrainingSession::where('session_date', $today)
            ->when($branchId, fn ($q) => $q->whereHas('group', fn ($g) => $g->where('branch_id', $branchId)))
            ->with(['group.program', 'trainer', 'facility'])
            ->orderBy('start_time')
            ->get()
            ->map(function ($session) use ($now, $endedSessionIds) {
                $session->has_attendance = false;
                if ($endedSessionIds->contains($session->id)) {
                    $session->has_attendance = $session->attendanceRecords()
                        ->where('status', '!=', AttendanceStatus::Expected)
                        ->exists();
                }
                // Calculate time remaining for upcoming sessions
                $session->time_remaining = null;
                if ($session->status->value === 'scheduled' && $session->start_time) {
                    $startDateTime = \Carbon\Carbon::parse($session->session_date->format('Y-m-d') . ' ' . $session->start_time);
                    if ($startDateTime->isAfter($now)) {
                        $diffMinutes = (int) $now->diffInMinutes($startDateTime);
                        if ($diffMinutes < 60) {
                            $session->time_remaining = $diffMinutes . ' ' . __('دقيقة');
                        } else {
                            $hours = intdiv($diffMinutes, 60);
                            $session->time_remaining = $hours . ' ' . __('ساعة');
                        }
                    }
                }
                return $session;
            });

        // --- Row 3 Right: Recent Payments ---
        $canViewFinancials = auth()->user()->hasPermission('invoices.list');
        $recentPayments = $canViewFinancials ? Payment::where('direction', 'inbound')->where('status', 'confirmed')
            ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
            ->with(['invoice.billable', 'payer'])
            ->orderByDesc('created_at')
            ->limit(10)
            ->get() : collect();

        return view('livewire.dashboard', [
            // Row 1
            'sessionsToday' => $sessionsToday,
            'trainersPresent' => $trainersPresent,
            'paymentsToday' => $paymentsToday,
            'expensesToday' => $expensesToday,
            'expensesThisMonth' => $expensesThisMonth,
            'cashExpensesThisMonth' => $cashExpensesThisMonth,
            'cashCollectionsThisMonth' => $cashCollectionsThisMonth,
            'expectedCashOnHand' => $expectedCashOnHand,
            'activeParticipants' => $activeParticipants,
            // Row 2
            'overdueInvoicesCount' => $overdueInvoicesCount,
            'pendingPayslips' => $pendingPayslips,
            'pendingDocuments' => $pendingDocuments,
            'lowStockItems' => $lowStockItems,
            'expiringMedicalCerts' => $expiringMedicalCerts,
            'attendanceNotTaken' => $attendanceNotTaken,
            // Row 3
            'todaySchedule' => $todaySchedule,
            'recentPayments' => $recentPayments,
            'canViewFinancials' => $canViewFinancials,
        ]);
    }
}
