<?php

namespace App\Http\Controllers;

use App\Models\Business;
use App\Services\BranchAccessService;
use App\Services\ManagementDashboardService;
use App\Support\Authorization\PermissionName;
use Carbon\CarbonImmutable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Support\Facades\Gate;
use Illuminate\Validation\ValidationException;
use Illuminate\View\View;

class DashboardController extends Controller implements HasMiddleware
{
    public static function middleware(): array
    {
        return ['permission:dashboard.view'];
    }

    public function __invoke(Request $request, ManagementDashboardService $service, BranchAccessService $branchAccess): View
    {
        $user = $request->user();
        Gate::forUser($user)->authorize(PermissionName::DASHBOARD_VIEW->value);
        $business = Business::first();
        $isSystemWide = $branchAccess->isSystemWide($user);

        if (! $user->can(PermissionName::REPORTS_VIEW->value)) {
            return view('dashboard', [
                'business' => $business,
                'managementDashboard' => false,
                'isSystemWide' => $isSystemWide,
            ]);
        }

        $allowedBranchIds = collect($branchAccess->accessibleBranchIds($user));
        $branches = $branchAccess->accessibleBranches($user);

        if ($allowedBranchIds->isEmpty()) {
            return view('dashboard', [
                'business' => $business,
                'managementDashboard' => true,
                'isSystemWide' => $isSystemWide,
                'branches' => $branches,
                'selectedBranchIds' => collect(),
                'selectedBranches' => collect(),
                'period' => 'today',
                'from' => now()->toDateString(),
                'to' => now()->toDateString(),
                'periodLabel' => 'Today',
                'dashboard' => null,
                'portfolio' => null,
                'portfolioMax' => 1,
            ]);
        }

        $validated = validator([
            'period' => $request->input('period', 'today'),
            'branch_ids' => $request->input('branch_ids', []),
            'from' => $request->input('from'),
            'to' => $request->input('to'),
        ], [
            'period' => ['required', 'in:today,yesterday,this-week,this-month,this-year,custom'],
            'branch_ids' => ['array'],
            'branch_ids.*' => ['integer', 'exists:branches,id'],
            'from' => ['nullable', 'required_if:period,custom', 'date'],
            'to' => ['nullable', 'required_if:period,custom', 'date'],
        ])->validate();

        $requestedBranchIds = collect($validated['branch_ids'] ?? [])->map(fn ($id) => (int) $id)->unique()->values();
        $branchAccess->assertBranchesAccessible($user, $requestedBranchIds->all());
        $selectedBranchIds = $requestedBranchIds->isEmpty() ? $allowedBranchIds : $requestedBranchIds;
        $selectedBranches = $branches->whereIn('id', $selectedBranchIds)->values();

        [$from, $to, $periodLabel] = $this->resolvePeriod(
            (string) $validated['period'],
            $validated['from'] ?? null,
            $validated['to'] ?? null,
        );

        $dashboard = $service->generate($selectedBranchIds->all(), $from, $to);
        $portfolio = $dashboard['portfolio_performance'];
        $portfolioMax = max(
            1,
            (float) $portfolio['total_outstanding'],
            (float) $portfolio['overdue'],
            (float) $portfolio['scheduled_due'],
            (float) $portfolio['collected'],
        );

        return view('dashboard', [
            'business' => $business,
            'managementDashboard' => true,
            'isSystemWide' => $isSystemWide,
            'branches' => $branches,
            'selectedBranchIds' => $selectedBranchIds,
            'selectedBranches' => $selectedBranches,
            'period' => $validated['period'],
            'from' => $from,
            'to' => $to,
            'periodLabel' => $periodLabel,
            'dashboard' => $dashboard,
            'portfolio' => $portfolio,
            'portfolioMax' => $portfolioMax,
        ]);
    }

    private function resolvePeriod(string $period, ?string $from, ?string $to): array
    {
        $now = CarbonImmutable::now();

        return match ($period) {
            'today' => [$now->toDateString(), $now->toDateString(), 'Today'],
            'yesterday' => [$now->subDay()->toDateString(), $now->subDay()->toDateString(), 'Yesterday'],
            'this-week' => [$now->startOfWeek()->toDateString(), $now->toDateString(), 'This week'],
            'this-month' => [$now->startOfMonth()->toDateString(), $now->toDateString(), 'This month'],
            'this-year' => [$now->startOfYear()->toDateString(), $now->toDateString(), 'This year'],
            'custom' => $this->customPeriod($from, $to),
        };
    }

    private function customPeriod(?string $from, ?string $to): array
    {
        if (! $from || ! $to) {
            throw ValidationException::withMessages(['from' => 'Custom dashboard range requires both start and end dates.']);
        }
        $fromDate = CarbonImmutable::parse($from)->startOfDay();
        $toDate = CarbonImmutable::parse($to)->startOfDay();
        if ($toDate->lt($fromDate)) {
            throw ValidationException::withMessages(['to' => 'The dashboard end date cannot be before the start date.']);
        }

        return [
            $fromDate->toDateString(),
            $toDate->toDateString(),
            $fromDate->format('d M Y').' – '.$toDate->format('d M Y'),
        ];
    }
}
