<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;

class BackofficeIpWhitelist
{
    /**
     * Middleware para verificar IP whitelist en TODAS las rutas del backoffice
     * incluyendo la página de login
     */
    public function handle(Request $request, Closure $next): Response
    {
        // Solo verificar si el whitelist está habilitado
        if (!config('backoffice.security.enable_ip_whitelist', false)) {
            return $next($request);
        }

        $clientIp = $this->getClientIp($request);
        $authorizedIps = config('backoffice.authorized_ips', []);
        
        // Optimización: Cache del resultado de verificación de IP por sesión
        $cacheKey = 'ip_verified_' . md5($clientIp);
        
        if (!session($cacheKey, false) && !$this->isIpAuthorized($clientIp, $authorizedIps)) {
            Log::warning('Unauthorized IP access attempt to backoffice', [
                'ip' => $clientIp,
                'user_agent' => $request->userAgent(),
                'url' => $request->fullUrl(),
                'route' => $request->route() ? $request->route()->getName() : 'unknown',
            ]);

            return response()->view('errors.403', [
                'message' => 'Acceso denegado desde tu ubicación',
                'ip' => $clientIp,
                'details' => 'Tu dirección IP no está autorizada para acceder al sistema de administración.',
                'contact_info' => 'Si necesitas acceso, contacta al administrador con tu IP: ' . $clientIp,
            ], 403);
        }

        // Guardar en sesión que la IP ya fue verificada (evita verificar en cada request)
        if (!session($cacheKey, false)) {
            session([$cacheKey => true]);
            Log::info('IP authorized and cached', ['ip' => $clientIp]);
        }

        return $next($request);
    }

    /**
     * Obtener IP real del cliente considerando proxies y CDNs
     */
    private function getClientIp(Request $request): string
    {
        // Cloudflare
        if ($request->header('CF-Connecting-IP')) {
            return $request->header('CF-Connecting-IP');
        }

        // Nginx proxy
        if ($request->header('X-Real-IP')) {
            return $request->header('X-Real-IP');
        }

        // Load balancer / proxy
        if ($request->header('X-Forwarded-For')) {
            $ips = explode(',', $request->header('X-Forwarded-For'));
            return trim($ips[0]);
        }

        // Directo
        return $request->ip();
    }

    /**
     * Verificar si la IP está autorizada
     */
    private function isIpAuthorized(string $clientIp, array $authorizedIps): bool
    {
        foreach ($authorizedIps as $authorizedIp) {
            // IP exacta
            if ($clientIp === $authorizedIp) {
                return true;
            }
            
            // Rango CIDR
            if (strpos($authorizedIp, '/') !== false && $this->ipInCidr($clientIp, $authorizedIp)) {
                return true;
            }
        }
        
        return false;
    }

    /**
     * Verificar si IP está en rango CIDR
     */
    private function ipInCidr(string $ip, string $cidr): bool
    {
        if (!str_contains($cidr, '/')) {
            return false;
        }

        list($subnet, $mask) = explode('/', $cidr);
        
        // Solo IPv4 por ahora
        if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) || 
            !filter_var($subnet, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            return false;
        }
        
        $mask = (int) $mask;
        if ($mask < 0 || $mask > 32) {
            return false;
        }
        
        return (ip2long($ip) & (-1 << (32 - $mask))) === (ip2long($subnet) & (-1 << (32 - $mask)));
    }
}