<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class ResolveAdminRoutePermission
{
    /** @var array<string, string> */
    private const MODULE_PREFIXES = [
        'accounting.' => 'accounting',
        'finance.' => 'finance',
        'school.' => 'school',
        'communication.' => 'communications',
        'extras.' => 'extras',
        'data.' => 'reports',
    ];

    /**
     * Routes that do not follow {module}.{action} permission naming.
     *
     * @var array<string, string>
     */
    private const ROUTE_PERMISSIONS = [
        'system.analytics.index' => 'analytics.view',
        'system.settings.index' => 'settings.view',
        'system.settings.update' => 'settings.edit',
        'system.email-settings.update' => 'settings.edit',
        'system.email-settings.test' => 'settings.edit',
        'system.users.index' => 'users.view',
        'system.users.invite' => 'users.create',
        'system.users.assign-roles' => 'users.edit',
        'system.audit.index' => 'reports.view',
        'system.backup.index' => 'reports.view',
        'system.backup.store' => 'settings.edit',
        'system.academic-years.index' => 'school.view',
        'system.report-builder.index' => 'reports.view',
        'system.report-builder.export' => 'reports.view',
        'system.import-export.history' => 'reports.view',
        'system.announcements.index' => 'communications.view',
        'system.announcements.create' => 'communications.create',
        'system.announcements.store' => 'communications.create',
        'system.announcements.edit' => 'communications.edit',
        'system.announcements.update' => 'communications.edit',
        'system.announcements.destroy' => 'communications.delete',
    ];

    public function handle(Request $request, Closure $next): Response
    {
        $user = $request->user();

        if ($user === null) {
            return redirect()->route('login');
        }

        if ($user->hasRole('Super Admin')) {
            return $next($request);
        }

        $routeName = $request->route()?->getName();

        if ($routeName === null || $routeName === 'admin.dashboard') {
            return $next($request);
        }

        $permission = self::permissionForRoute($routeName);

        if ($permission !== null && ! $user->can($permission)) {
            abort(403);
        }

        return $next($request);
    }

    public static function permissionForRoute(string $routeName): ?string
    {
        if (isset(self::ROUTE_PERMISSIONS[$routeName])) {
            return self::ROUTE_PERMISSIONS[$routeName];
        }

        if (str_starts_with($routeName, 'accounting.fixed-assets.')) {
            return self::permissionForModuleRoute('fixed_assets', $routeName);
        }

        $module = null;

        foreach (self::MODULE_PREFIXES as $prefix => $moduleKey) {
            if (str_starts_with($routeName, $prefix)) {
                $module = $moduleKey;
                break;
            }
        }

        if (str_starts_with($routeName, 'system.')) {
            return self::permissionForSystemRoute($routeName);
        }

        if ($module === null) {
            return null;
        }

        return self::permissionForModuleRoute($module, $routeName);
    }

    private static function permissionForModuleRoute(string $module, string $routeName): string
    {
        $action = str_contains($routeName, '.') ? substr($routeName, strrpos($routeName, '.') + 1) : $routeName;

        if (in_array($action, ['create', 'store'], true)) {
            return "{$module}.create";
        }

        if (in_array($action, ['edit', 'update', 'void', 'depreciate', 'complete', 'match', 'convert', 'borrow', 'publish', 'generate', 'compile', 'submit', 'approve', 'assign', 'mark', 'return', 'pay', 'retry', 'duplicate', 'send', 'reject', 'upload', 'confirm'], true)) {
            return "{$module}.edit";
        }

        if (in_array($action, ['destroy', 'delete'], true)) {
            return "{$module}.delete";
        }

        if (in_array($action, ['pdf', 'export', 'template'], true)) {
            return "{$module}.view";
        }

        return "{$module}.view";
    }

    private static function permissionForSystemRoute(string $routeName): ?string
    {
        if (str_starts_with($routeName, 'system.announcements.')) {
            return self::ROUTE_PERMISSIONS[$routeName] ?? 'communications.view';
        }

        return self::ROUTE_PERMISSIONS[$routeName] ?? 'settings.view';
    }
}
