<?php

/**
 * Funciones de manejo de API REST para el plugin SIIP Available IPs
 */

/**
 * Maneja las peticiones API REST basadas en eventos
 */
function handleApiRequest($data, $log) {
    header('Content-Type: application/json');
    
    try {
        // Validar que exista el tipo de evento
        if (empty($data['type'])) {
            echo json_encode([
                'success' => false,
                'error' => 'Missing event type',
                'message' => 'The "type" field is required'
            ]);
            return;
        }
        
        $eventType = $data['type'];
        $log->appendLog("Procesando evento API: $eventType");
        
        // Manejar diferentes tipos de eventos
        switch ($eventType) {
            case 'event.ip_request':
                handleIpRequest($data, $log);
                break;
                
            case 'event.ip_check':
                handleIpCheck($data, $log);
                break;
                
            case 'event.ip_validate':
                handleIpValidate($data, $log);
                break;
                
            default:
                echo json_encode([
                    'success' => false,
                    'error' => 'Unknown event type',
                    'message' => "Event type '$eventType' is not supported",
                    'supported_events' => [
                        'event.ip_request',
                        'event.ip_check',
                        'event.ip_validate'
                    ]
                ]);
        }
    } catch (Exception $e) {
        $log->appendLog('Error en API request: ' . $e->getMessage());
        echo json_encode([
            'success' => false,
            'error' => 'Internal error',
            'message' => $e->getMessage()
        ]);
    }
}

/**
 * Maneja el evento event.ip_request - Buscar IPs disponibles en un segmento
 */
function handleIpRequest($data, $log) {
    // Validar segmento
    if (!isset($data['segment'])) {
        echo json_encode([
            'success' => false,
            'error' => 'Missing segment',
            'message' => 'The "segment" field is required for event.ip_request'
        ]);
        return;
    }
    
    $segment = $data['segment'];
    $verifyPing = isset($data['verify_ping']) && $data['verify_ping'] === true;
    $pingLimit = isset($data['ping_limit']) ? intval($data['ping_limit']) : 0;
    
    if ($verifyPing) {
        $limitMsg = $pingLimit > 0 ? "límite: $pingLimit IPs" : "sin límite";
        $log->appendLog("API: Verificación por ping habilitada para segmento $segment ($limitMsg)");
    } else {
        $log->appendLog("API: Buscando IPs en segmento $segment (sin verificación por ping)");
    }
    
    // Cargar configuración
    $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
    $config = $configManager->loadConfig();
    
    if (empty($config['ipserver']) || empty($config['unmsApiToken'])) {
        echo json_encode([
            'success' => false,
            'error' => 'Plugin not configured',
            'message' => 'Plugin configuration is incomplete'
        ]);
        return;
    }
    
    // Buscar IPs
    $apiUrl = "https://{$config['ipserver']}/nms/api/v2.1/devices/ips?suspended=true&management=true&includeObsolete=true";
    $apiToken = $config['unmsApiToken'];
    
    $ipService = new \SiipAvailableIps\IpSearchService($apiUrl, $apiToken, $log, $config);
    $resultado = $ipService->buscarIpsDisponibles($segment, $verifyPing, $pingLimit);
    
    // Formatear respuesta para API
    if ($resultado['success']) {
        // Filtrar IPs administrativas - Solo devolver IPs aptas para clientes
        $clientAvailableIps = array_filter($resultado['data'], function($ip) use ($config) {
            return !\SiipAvailableIps\IpSearchService::isAdminIp($ip, $config);
        });
        $clientAvailableIps = array_values($clientAvailableIps); // Reindexar array
        
        $log->appendLog("API: Filtrando IPs administrativas. Total disponibles: " . count($resultado['data']) . ", Aptas para clientes: " . count($clientAvailableIps));
        
        $response = [
            'success' => true,
            'event' => 'event.ip_request',
            'segment' => $resultado['segment'],
            'data' => [
                'available' => $clientAvailableIps,
                'used' => $resultado['used']
            ],
            'count' => [
                'available' => count($clientAvailableIps),
                'used' => count($resultado['used']),
                'admin_filtered' => count($resultado['data']) - count($clientAvailableIps)
            ],
            'ping_verified' => $resultado['ping_verified'],
            'message' => sprintf(
                'Se encontraron %d IPs aptas para clientes en el segmento %s (%d IPs administrativas filtradas)',
                count($clientAvailableIps),
                $resultado['segment'],
                count($resultado['data']) - count($clientAvailableIps)
            )
        ];
        
        // Agregar estadísticas de ping si se verificó
        if ($resultado['ping_verified'] && isset($resultado['ping_stats'])) {
            $response['ping_stats'] = $resultado['ping_stats'];
            
            // Filtrar IPs que responden de las IPs de cliente
            if (isset($resultado['ping_responding'])) {
                $clientPingResponding = array_filter($resultado['ping_responding'], function($ip) use ($config) {
                    return !\SiipAvailableIps\IpSearchService::isAdminIp($ip, $config);
                });
                $response['ping_responding'] = array_values($clientPingResponding);
            }
        }
        
        echo json_encode($response);
    } else {
        echo json_encode([
            'success' => false,
            'error' => 'IP search failed',
            'message' => $resultado['message']
        ]);
    }
}

/**
 * Maneja el evento event.ip_check - Verificar si una IP específica está disponible
 */
function handleIpCheck($data, $log) {
    // Validar parámetros
    if (!isset($data['ip'])) {
        echo json_encode([
            'success' => false,
            'error' => 'Missing IP address',
            'message' => 'The "ip" field is required for event.ip_check'
        ]);
        return;
    }
    
    $ipToCheck = $data['ip'];
    $log->appendLog("API: Verificando disponibilidad de IP $ipToCheck");
    
    // Extraer segmento de la IP
    $parts = explode('.', $ipToCheck);
    if (count($parts) !== 4 || $parts[0] !== '172' || $parts[1] !== '16') {
        echo json_encode([
            'success' => false,
            'error' => 'Invalid IP format',
            'message' => 'IP must be in format 172.16.X.X'
        ]);
        return;
    }
    
    $segment = $parts[2];
    
    // Cargar configuración y buscar
    $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
    $config = $configManager->loadConfig();
    
    if (empty($config['ipserver']) || empty($config['unmsApiToken'])) {
        echo json_encode([
            'success' => false,
            'error' => 'Plugin not configured',
            'message' => 'Plugin configuration is incomplete'
        ]);
        return;
    }
    
    $apiUrl = "https://{$config['ipserver']}/nms/api/v2.1/devices/ips?suspended=true&management=true&includeObsolete=true";
    $apiToken = $config['unmsApiToken'];
    
    // Verificar si se solicita ping
    $verifyPing = isset($data['verify_ping']) && $data['verify_ping'] === true;
    
    $ipService = new \SiipAvailableIps\IpSearchService($apiUrl, $apiToken, $log, $config);
    
    // Si NO se solicita ping, buscar normalmente
    if (!$verifyPing) {
        $resultado = $ipService->buscarIpsDisponibles($segment, false);
        
        if ($resultado['success']) {
            $isAvailable = in_array($ipToCheck, $resultado['data']);
            $isUsed = in_array($ipToCheck, $resultado['used']);
            $ipType = \SiipAvailableIps\IpSearchService::getIpType($ipToCheck, $config);
            
            // Debug logging
            $log->appendLog("API Check (sin ping) - IP: $ipToCheck");
            $log->appendLog("  - En lista disponibles: " . ($isAvailable ? 'SÍ' : 'NO'));
            $log->appendLog("  - En lista usadas: " . ($isUsed ? 'SÍ' : 'NO'));
            $log->appendLog("  - Total disponibles: " . count($resultado['data']));
            $log->appendLog("  - Total usadas: " . count($resultado['used']));
            
            
            // Determinar status con información de tipo de IP
            $status = 'unknown';
            if ($isAvailable) {
                $status = $ipType['type'] === 'admin' 
                    ? 'IP disponible pero para uso administrativo' 
                    : 'available';
            } elseif ($isUsed) {
                $status = $ipType['type'] === 'admin' 
                    ? 'IP en uso y además para uso administrativo' 
                    : 'used';
            }
            
            echo json_encode([
                'success' => true,
                'event' => 'event.ip_check',
                'ip' => $ipToCheck,
                'status' => $status,
                'available' => $isAvailable,
                'used' => $isUsed,
                'ip_type' => $ipType,
                'ping_verified' => false
            ]);
        } else {
            echo json_encode([
                'success' => false,
                'error' => 'IP check failed',
                'message' => $resultado['message']
            ]);
        }
        return;
    }
    
    // Si SÍ se solicita ping, hacer ping SOLO a esta IP específica
    $log->appendLog("API: Verificación por ping habilitada para IP $ipToCheck");
    
    // Primero verificar si está en UISP
    $resultado = $ipService->buscarIpsDisponibles($segment, false);
    
    if (!$resultado['success']) {
        echo json_encode([
            'success' => false,
            'error' => 'IP check failed',
            'message' => $resultado['message']
        ]);
        return;
    }
    
    $isAvailable = in_array($ipToCheck, $resultado['data']);
    $isUsed = in_array($ipToCheck, $resultado['used']);
    $ipType = \SiipAvailableIps\IpSearchService::getIpType($ipToCheck, $config);
    
    // Debug logging
    $log->appendLog("API Check - IP: $ipToCheck");
    $log->appendLog("  - En lista disponibles: " . ($isAvailable ? 'SÍ' : 'NO'));
    $log->appendLog("  - En lista usadas: " . ($isUsed ? 'SÍ' : 'NO'));
    $log->appendLog("  - Total disponibles: " . count($resultado['data']));
    $log->appendLog("  - Total usadas: " . count($resultado['used']));
    
    
    // Hacer ping solo a esta IP
    $pingService = new \SiipAvailableIps\PingService($log);
    $pingResult = $pingService->pingIp($ipToCheck, 1); // 1 segundo de timeout
    $pingResponds = $pingResult['responding'];
    
    $log->appendLog("Ping a $ipToCheck: " . ($pingResponds ? 'RESPONDE' : 'NO RESPONDE'));
    
    // Determinar status
    $status = 'unknown';
    if ($isAvailable) {
        $status = $ipType['type'] === 'admin' 
            ? 'IP disponible pero para uso administrativo' 
            : 'available';
    } elseif ($isUsed) {
        $status = $ipType['type'] === 'admin' 
            ? 'IP en uso y además para uso administrativo' 
            : 'used';
    }
    
    $response = [
        'success' => true,
        'event' => 'event.ip_check',
        'ip' => $ipToCheck,
        'status' => $status,
        'available' => $isAvailable,
        'used' => $isUsed,
        'ip_type' => $ipType,
        'ping_verified' => true,
        'ping_responds' => $pingResponds
    ];
    
    // Si la IP responde a ping pero está marcada como disponible, es una advertencia
    if ($pingResponds && $isAvailable) {
        $response['warning'] = 'IP responde a ping pero no está registrada en UISP';
    }
    
    // Log de la respuesta antes de enviarla
    $log->appendLog("Respuesta JSON: " . json_encode($response));
    
    echo json_encode($response);
}

/**
 * Maneja el evento event.ip_validate - Validar IP individual usando búsqueda de sitios
 */
function handleIpValidate($data, $log) {
    // Validar IP
    if (!isset($data['ip'])) {
        echo json_encode([
            'success' => false,
            'error' => 'Missing IP',
            'message' => 'The "ip" field is required for event.ip_validate'
        ]);
        return;
    }
    
    $ip = $data['ip'];
    
    // Validar formato de IP
    if (!filter_var($ip, FILTER_VALIDATE_IP)) {
        echo json_encode([
            'success' => false,
            'error' => 'Invalid IP',
            'message' => "The IP '$ip' is not valid"
        ]);
        return;
    }
    
    // Obtener configuración
    $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
    $config = $configManager->loadConfig();
    
    // Verificar que tengamos las credenciales necesarias
    if (empty($config['unmsApiToken']) || empty($config['ipserver'])) {
        echo json_encode([
            'success' => false,
            'error' => 'Missing configuration',
            'message' => 'UNMS API token or server not configured'
        ]);
        return;
    }
    
    try {
        // Crear instancia del validador
        $baseUrl = 'https://' . $config['ipserver'];
        $ipValidator = new \SiipAvailableIps\IpValidator(
            $baseUrl,
            $config['unmsApiToken'],
            $log
        );
        
        // Validar si la IP está en uso
        $isInUse = $ipValidator->isIpInUse($ip);
        
        // Preparar respuesta
        $response = [
            'success' => true,
            'event' => 'event.ip_validate',
            'ip' => $ip,
            'in_use' => $isInUse,
            'available' => !$isInUse,
            'validation_method' => 'site_search'
        ];
        
        if ($isInUse) {
            $response['message'] = 'IP encontrada en UISP (búsqueda de sitios)';
        } else {
            $response['message'] = 'IP no encontrada en UISP';
        }
        
        echo json_encode($response);
        
    } catch (\Exception $e) {
        $log->appendLog('Error en validación de IP: ' . $e->getMessage());
        echo json_encode([
            'success' => false,
            'error' => 'Validation error',
            'message' => $e->getMessage()
        ]);
    }
}
