<?php

namespace App\Http\Controllers;

use App\Enums\DeclarationStatus;
use App\Enums\WorkspaceUserRole;
use App\Models\Declaration;
use App\Models\Workspace;
use App\Models\WorkspaceUser;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Inertia\Inertia;
use Inertia\Response;

class DashboardController extends Controller
{
    /**
     * Display the command center dashboard with KPI cards and urgent declarations.
     */
    public function __invoke(Request $request): Response
    {
        $user = $request->user();
        $workspaceId = $request->session()->get('current_workspace_id');
        $workspace = $workspaceId ? Workspace::query()->find($workspaceId) : null;

        if (! $workspace || ! $user) {
            return Inertia::render('Dashboard', [
                'stats' => null,
                'statCards' => [],
                'declarations' => [],
                'alerts' => [],
                'workspaceName' => null,
                'roleLabel' => null,
                'isWorker' => false,
                'declarationsUrl' => null,
                'clientsUrl' => null,
                'viewAllAlertsUrl' => null,
            ]);
        }

        /** @var WorkspaceUser|null $workspaceUser */
        $workspaceUser = $workspace->users()
            ->where('users.id', $user->id)
            ->first()
            ?->pivot;

        if (! $workspaceUser) {
            abort(404);
        }

        $cacheKey = "dashboard:{$workspace->id}:{$user->id}";

        $dashboardData = Cache::remember($cacheKey, 300, function () use ($workspace, $user, $workspaceUser) {
            $baseQuery = fn () => $workspace->declarations()
                ->active()
                ->whereNotIn('status', [DeclarationStatus::Termine, DeclarationStatus::MiseEnDemeure, DeclarationStatus::Ferme])
                ->forUser($user, $workspaceUser);

            $overdue = $baseQuery()
                ->where('due_date', '<', now()->startOfDay())
                ->count();

            $dueThisWeek = $baseQuery()
                ->whereBetween('due_date', [now()->startOfDay(), now()->addDays(7)->endOfDay()])
                ->count();

            $enAttenteClient = $baseQuery()
                ->where('status', DeclarationStatus::EnAttenteClient)
                ->count();

            $enCours = $baseQuery()
                ->where('status', DeclarationStatus::EnCours)
                ->count();

            $alerts = $this->buildAlerts($baseQuery);

            return [
                'overdue' => $overdue,
                'dueThisWeek' => $dueThisWeek,
                'enAttenteClient' => $enAttenteClient,
                'enCours' => $enCours,
                'alerts' => $alerts,
            ];
        });

        $urgentDeclarations = $workspace->declarations()
            ->active()
            ->whereNotIn('status', [DeclarationStatus::Termine, DeclarationStatus::MiseEnDemeure, DeclarationStatus::Ferme])
            ->forUser($user, $workspaceUser)
            ->with('client:id,company_name', 'assignee:id,name')
            ->orderByRaw('CASE WHEN due_date IS NULL THEN 1 ELSE 0 END, due_date ASC')
            ->limit(15)
            ->get()
            ->map(fn (Declaration $d) => [
                'id' => $d->id,
                'title' => $d->title,
                'type' => $d->type->value,
                'typeLabel' => $this->typeLabels()[$d->type->value] ?? $d->type->value,
                'clientName' => $d->client?->company_name ?? 'Client supprimé',
                'assigneeName' => $d->assignee?->name,
                'status' => $d->status->value,
                'statusLabel' => DeclarationStatus::labels()[$d->status->value] ?? $d->status->value,
                'dueDate' => $d->due_date?->format('Y-m-d'),
                'showUrl' => route('declarations.show', $d),
            ])
            ->all();

        $roleLabel = $this->roleLabels()[$workspaceUser->role->value] ?? $workspaceUser->role->value;
        $isWorker = $workspaceUser->role->is(WorkspaceUserRole::Worker);

        $assigneeParam = $isWorker ? ['assignee' => $user->id] : [];

        $statCards = [
            [
                'label' => 'En retard',
                'count' => $dashboardData['overdue'],
                'status' => 'danger',
                'href' => route('declarations.index', array_merge(['overdue' => 1], $assigneeParam)),
            ],
            [
                'label' => 'Cette semaine',
                'count' => $dashboardData['dueThisWeek'],
                'status' => 'warning',
                'href' => route('declarations.index', array_merge(['due_this_week' => 1], $assigneeParam)),
            ],
            [
                'label' => 'En attente client',
                'count' => $dashboardData['enAttenteClient'],
                'status' => 'info',
                'href' => route('declarations.index', array_merge(['status' => DeclarationStatus::EnAttenteClient], $assigneeParam)),
            ],
            [
                'label' => 'En cours',
                'count' => $dashboardData['enCours'],
                'status' => 'success',
                'href' => route('declarations.index', array_merge(['status' => DeclarationStatus::EnCours], $assigneeParam)),
            ],
        ];

        return Inertia::render('Dashboard', [
            'stats' => $dashboardData,
            'statCards' => $statCards,
            'declarations' => $urgentDeclarations,
            'alerts' => $dashboardData['alerts'],
            'workspaceName' => $workspace->name,
            'roleLabel' => $roleLabel,
            'isWorker' => $isWorker,
            'declarationsUrl' => route('declarations.index'),
            'clientsUrl' => route('clients.index'),
            'viewAllAlertsUrl' => route('declarations.index', ['filter' => 'alerts']),
        ]);
    }

    /**
     * Build priority alerts from declarations, sorted by severity and urgency.
     *
     * @param  \Closure  $baseQuery  A closure that returns a fresh query builder with workspace/user scoping applied
     * @return array<int, array<string, mixed>>
     */
    private function buildAlerts(\Closure $baseQuery): array
    {
        $typeLabels = $this->typeLabels();
        $today = now()->startOfDay();

        // Critical: overdue declarations (past deadline), excluding en_attente_client (handled by info)
        $critical = $baseQuery()
            ->whereNotNull('due_date')
            ->where('due_date', '<', $today)
            ->where('status', '!=', DeclarationStatus::EnAttenteClient)
            ->with('client:id,company_name')
            ->orderBy('due_date', 'asc')
            ->limit(20)
            ->get()
            ->map(fn (Declaration $d) => [
                'id' => $d->id,
                'severity' => 'critical',
                'clientName' => $d->client?->company_name ?? 'Client supprimé',
                'declarationType' => $d->type->value,
                'typeLabel' => $typeLabels[$d->type->value] ?? $d->type->value,
                'daysValue' => (int) abs($today->diffInDays($d->due_date)),
                'daysLabel' => abs($today->diffInDays($d->due_date)) <= 1 ? 'jour en retard' : 'jours en retard',
                'showUrl' => route('declarations.show', $d),
            ]);

        // Warning: approaching deadlines (due within 3 days)
        $warning = $baseQuery()
            ->whereNotNull('due_date')
            ->whereBetween('due_date', [$today, now()->addDays(3)->endOfDay()])
            ->with('client:id,company_name')
            ->orderBy('due_date', 'asc')
            ->limit(20)
            ->get()
            ->map(fn (Declaration $d) => [
                'id' => $d->id,
                'severity' => 'warning',
                'clientName' => $d->client?->company_name ?? 'Client supprimé',
                'declarationType' => $d->type->value,
                'typeLabel' => $typeLabels[$d->type->value] ?? $d->type->value,
                'daysValue' => (int) $today->diffInDays($d->due_date),
                'daysLabel' => $today->diffInDays($d->due_date) <= 1 ? 'jour restant' : 'jours restants',
                'showUrl' => route('declarations.show', $d),
            ]);

        // Info: waiting on client for >3 days
        $info = $baseQuery()
            ->where('status', DeclarationStatus::EnAttenteClient)
            ->where('updated_at', '<', now()->subDays(3))
            ->with('client:id,company_name')
            ->orderBy('updated_at', 'asc')
            ->limit(20)
            ->get()
            ->map(fn (Declaration $d) => [
                'id' => $d->id,
                'severity' => 'info',
                'clientName' => $d->client?->company_name ?? 'Client supprimé',
                'declarationType' => $d->type->value,
                'typeLabel' => $typeLabels[$d->type->value] ?? $d->type->value,
                'daysValue' => (int) abs($today->diffInDays($d->updated_at)),
                'daysLabel' => abs($today->diffInDays($d->updated_at)) <= 1 ? 'jour en attente' : 'jours en attente',
                'showUrl' => route('declarations.show', $d),
            ]);

        return $critical->concat($warning)->concat($info)->take(20)->values()->toArray();
    }

    /**
     * Get declaration type labels.
     *
     * @return array<string, string>
     */
    protected function typeLabels(): array
    {
        return [
            'vat' => 'TVA',
            'vat_monthly' => 'TVA mensuelle',
            'vat_quarterly' => 'TVA trimestrielle',
            'corporate_tax' => 'IS',
            'income_tax' => 'IR',
            'cnss' => 'CNSS',
            'annual_balance' => 'Bilan',
            'other' => 'Autre',
        ];
    }

    /**
     * Get workspace user role labels.
     *
     * @return array<string, string>
     */
    protected function roleLabels(): array
    {
        return [
            WorkspaceUserRole::Owner => 'Propriétaire',
            WorkspaceUserRole::Manager => 'Manager',
            WorkspaceUserRole::Worker => 'Collaborateur',
        ];
    }
}
