<?php

declare(strict_types=1);

namespace App\Http\Middleware;

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

/**
 * Middleware para verificar acceso a la PWA multi-rol.
 *
 * Permite acceso a usuarios con roles: collector, supervisor, admin.
 * Todos los usuarios deben tener empresa asignada y suscripcion activa.
 * SuperAdmin queda fuera del scope de la PWA.
 */
class EnsurePwaAccess
{
    /**
     * Roles permitidos en la PWA (usando Spatie Permissions).
     *
     * Público porque `App\Services\Sync\CapturerResolver` también lo usa para
     * decidir si un usuario de la cola offline puede ser capturador.
     */
    public const ALLOWED_ROLES = ['collector', 'supervisor', 'admin'];

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

        if (! $user) {
            return response()->json([
                'message' => 'No autenticado.',
            ], 401);
        }

        // Verificar rol usando Spatie hasAnyRole()
        if (! $user->hasAnyRole(self::ALLOWED_ROLES)) {
            return response()->json([
                'message' => 'Acceso denegado. Solo usuarios autorizados pueden usar la app.',
            ], 403);
        }

        // Verificar que tiene company asignada (company-scoped access)
        if (! $user->company_id) {
            return response()->json([
                'message' => 'Usuario sin empresa asignada.',
            ], 403);
        }

        // Verificar suscripcion activa
        if (! $user->hasActiveSubscription()) {
            return response()->json([
                'message' => 'La suscripcion de tu empresa ha expirado.',
            ], 403);
        }

        // Verificar que el token tiene una habilidad PWA específica (pwa:collector, pwa:supervisor,
        // pwa:admin). Se accede a ->abilities directamente para evitar que tokenCan() acepte el
        // comodín '*' de Sanctum — un token con '*' debería ser rechazado porque los tokens PWA
        // siempre llevan una habilidad de rol específica del flujo de login.
        //
        // La comprobación is_array() excluye los mocks de Mockery que usa Sanctum::actingAs()
        // en tests, cuya propiedad ->abilities devuelve false (no un array real).
        $currentToken = $user->currentAccessToken();
        $abilities = $currentToken?->abilities;

        if (is_array($abilities)) {
            $hasPwaAbility = in_array('pwa:collector', $abilities, true)
                || in_array('pwa:supervisor', $abilities, true)
                || in_array('pwa:admin', $abilities, true);

            if (! $hasPwaAbility) {
                return response()->json([
                    'message' => 'Token sin permisos PWA. Inicia sesión nuevamente.',
                ], 403);
            }
        }

        return $next($request);
    }
}
