<?php

/**
 * Sender ID API - Main entry point
 * This file processes all API requests and routes them to the appropriate controller
 */

// Include required files
require_once __DIR__ . '/config/config.php';
require_once __DIR__ . '/config/database.php';
require_once __DIR__ . '/authentication.php';
require_once __DIR__ . '/utilities/Logger.php';
require_once __DIR__ . '/utilities/RateLimiter.php';
require_once __DIR__ . '/controllers/SenderIdController.php';
require_once __DIR__ . '/controllers/IPWhitelistController.php';
require_once __DIR__ . '/models/ApiKey.php';
require_once __DIR__ . '/models/IPWhitelist.php';
require_once __DIR__ . '/models/SenderIdRequest.php';  // Ensure SenderIdController can use SenderIdRequest

// Error reporting for debugging
error_reporting(E_ALL);
ini_set('display_errors', 1);

// Set response content type to JSON
header('Content-Type: application/json');

// Allow CORS (Cross-Origin Resource Sharing)
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Authorization, Content-Type');

// Handle preflight OPTIONS request
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

// Record start time for performance tracking
$startTime = microtime(true);

// Get request method and path
$method = $_SERVER['REQUEST_METHOD'];
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

// Strip base path if needed (e.g., /api/v1)
$basePath = '/api/v1';
if (strpos($path, $basePath) === 0) {
    $path = substr($path, strlen($basePath));
}

// Parse path segments
$segments = array_values(array_filter(explode('/', $path)));

// Extract API version if present
$version = API_VERSION; // Default from config
if (!empty($segments) && preg_match('/^v\d+$/', $segments[0])) {
    $version = array_shift($segments);
}

// Get client IP address
$clientIp = $_SERVER['REMOTE_ADDR'];
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $clientIp = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

// Authenticate the API key
$apiKey = Authentication::getApiKey();
$clientId = Authentication::validateApiKey($apiKey);

// Initialize response array
$response = [
    'success' => false,
    'error' => [
        'message' => 'Authentication failed',
        'code' => 'AUTH_FAILED'
    ]
];

// HTTP status code (default: 401 Unauthorized)
$statusCode = 401;

// Only process if authenticated or it's an OPTIONS request
if ($clientId !== false) {
    // Whitelist endpoint exclusions - endpoints that don't need whitelist checks
    $whitelistExclusions = [
        '/whitelist/add',
        '/whitelist/remove',
        '/whitelist'
    ];
    
    // Check IP whitelist for non-excluded endpoints
    if (!in_array($path, $whitelistExclusions)) {
        if (!Authentication::checkIpWhitelist($clientId, $clientIp)) {
            $response = [
                'success' => false,
                'error' => [
                    'message' => 'IP address not whitelisted',
                    'code' => 'UNAUTHORIZED_IP'
                ]
            ];
            $statusCode = 403; // Forbidden
            
            // Log the unauthorized IP attempt
            Logger::log(Logger::WARNING, "Unauthorized IP attempt", [
                'client_id' => $clientId,
                'ip_address' => $clientIp,
                'endpoint' => $path
            ]);
            
            // Output response and exit
            http_response_code($statusCode);
            echo json_encode($response, JSON_PRETTY_PRINT);
            exit;
        }
    }
    
    // Check rate limits
    $endpoint = $path;
    $rateLimitResult = RateLimiter::checkRateLimit($clientId, $endpoint);
    
    // Add rate limit headers
    header('X-RateLimit-Limit-Hour: ' . $rateLimitResult['hourly']['limit']);
    header('X-RateLimit-Remaining-Hour: ' . $rateLimitResult['hourly']['remaining']);
    header('X-RateLimit-Reset-Hour: ' . $rateLimitResult['hourly']['reset']);
    
    header('X-RateLimit-Limit-Day: ' . $rateLimitResult['daily']['limit']);
    header('X-RateLimit-Remaining-Day: ' . $rateLimitResult['daily']['remaining']);
    header('X-RateLimit-Reset-Day: ' . $rateLimitResult['daily']['reset']);
    
    if ($rateLimitResult['allowed']) {
        // Process the request based on the path and method
        $statusCode = 200;
        
        // Parse query parameters and request body
        $queryParams = $_GET;
        
        // Get JSON body for POST/PUT requests
        $body = [];
        if ($method === 'POST' || $method === 'PUT') {
            $inputJSON = file_get_contents('php://input');
            $body = json_decode($inputJSON, true);
            
            // If JSON parsing failed, try form data
            if ($body === null && !empty($inputJSON)) {
                parse_str($inputJSON, $body);
            }
            
            // Fallback to POST/PUT arrays
            if ($body === null) {
                $body = $_POST ?: [];
            }
        }
        
        $senderIdController = new SenderIdController();
        $ipWhitelistController = new IPWhitelistController();
        
        // Route the request
        switch (true) {
            // Create a new sender ID request
            case $method === 'POST' && $path === '/sender-id' || $path === '/sender-id/':
                $response = $senderIdController->create($body, $clientId, $clientIp);
                $statusCode = $response['success'] ? 201 : 400;
                break;
                
            // Get a sender ID request by request ID
            case $method === 'GET' && preg_match('/^\/sender-id\/request\/([^\/]+)$/', $path, $matches):
                $requestId = $matches[1];
                $response = $senderIdController->getByRequestId($requestId, $clientId);
                $statusCode = $response['success'] ? 200 : ($response['error']['code'] === 'NOT_FOUND' ? 404 : 400);
                break;
                
            // Get sender ID requests by sender ID
            case $method === 'GET' && preg_match('/^\/sender-id\/([^\/]+)$/', $path, $matches):
                $senderId = $matches[1];
                $response = $senderIdController->getBySenderId($senderId, $clientId);
                $statusCode = $response['success'] ? 200 : ($response['error']['code'] === 'NOT_FOUND' ? 404 : 400);
                break;
                
            // Get all sender ID requests
            case $method === 'GET' && ($path === '/sender-id' || $path === '/sender-id/'):
                $response = $senderIdController->getAll($queryParams, $clientId);
                $statusCode = $response['success'] ? 200 : 400;
                break;
                
            // IP whitelist - add IP
            case $method === 'POST' && $path === '/whitelist/add':
                if (empty($body['ip_address'])) {
                    $response = [
                        'success' => false,
                        'error' => [
                            'message' => 'IP address is required',
                            'code' => 'MISSING_IP_ADDRESS'
                        ]
                    ];
                    $statusCode = 400;
                } else {
                    $description = isset($body['description']) ? $body['description'] : null;
                    $response = $ipWhitelistController->addIP($apiKey, $body['ip_address'], $description);
                    $statusCode = $response['success'] ? 200 : 400;
                }
                break;
                
            // IP whitelist - remove IP
            case $method === 'POST' && $path === '/whitelist/remove':
                if (empty($body['ip_address'])) {
                    $response = [
                        'success' => false,
                        'error' => [
                            'message' => 'IP address is required',
                            'code' => 'MISSING_IP_ADDRESS'
                        ]
                    ];
                    $statusCode = 400;
                } else {
                    $response = $ipWhitelistController->removeIP($apiKey, $body['ip_address']);
                    $statusCode = $response['success'] ? 200 : 400;
                }
                break;
                
            // IP whitelist - get all IPs
            case $method === 'GET' && $path === '/whitelist':
                $response = $ipWhitelistController->getAll($apiKey);
                $statusCode = $response['success'] ? 200 : 400;
                break;
                
            // API key management - generate new key
            case $method === 'POST' && $path === '/keys/generate':
                $expiryDate = isset($body['expiry_date']) ? $body['expiry_date'] : null;
                $response = ApiKey::generate($clientId, $expiryDate);
                $statusCode = $response['success'] ? 201 : 400;
                break;
                
            // API key management - list all keys
            case $method === 'GET' && $path === '/keys':
                $response = ApiKey::getAllForClient($clientId);
                $statusCode = $response['success'] ? 200 : 400;
                break;
                
            // API key management - deactivate key
            case $method === 'POST' && $path === '/keys/deactivate':
                if (empty($body['api_key'])) {
                    $response = [
                        'success' => false,
                        'error' => [
                            'message' => 'API key is required',
                            'code' => 'MISSING_API_KEY'
                        ]
                    ];
                    $statusCode = 400;
                } else {
                    $response = ApiKey::deactivate($body['api_key']);
                    $statusCode = $response['success'] ? 200 : ($response['error']['code'] === 'NOT_FOUND' ? 404 : 400);
                }
                break;
                
            // API key management - rotate key
            case $method === 'POST' && $path === '/keys/rotate':
                if (empty($body['api_key'])) {
                    $response = [
                        'success' => false,
                        'error' => [
                            'message' => 'API key is required',
                            'code' => 'MISSING_API_KEY'
                        ]
                    ];
                    $statusCode = 400;
                } else {
                    $expiryDate = isset($body['expiry_date']) ? $body['expiry_date'] : null;
                    $response = ApiKey::rotate($body['api_key'], $expiryDate);
                    $statusCode = $response['success'] ? 200 : ($response['error']['code'] === 'NOT_FOUND' ? 404 : 400);
                }
                break;
                
            // Default: Route not found
            default:
                $response = [
                    'success' => false,
                    'error' => [
                        'message' => 'Route not found',
                        'code' => 'NOT_FOUND'
                    ]
                ];
                $statusCode = 404;
                break;
        }
    } else {
        // Rate limit exceeded
        $response = [
            'success' => false,
            'error' => [
                'message' => $rateLimitResult['message'],
                'code' => 'RATE_LIMIT_EXCEEDED'
            ]
        ];
        
        // Add retry-after header
        if (isset($rateLimitResult['retry_after'])) {
            header('Retry-After: ' . $rateLimitResult['retry_after']);
        }
        
        $statusCode = 429; // Too Many Requests
    }
}

// Calculate execution time
$executionTime = (microtime(true) - $startTime) * 1000; // in milliseconds

// Log the API call
Logger::logApiRequest(
    $clientId ?: 'unauthorized',
    $path,
    $method,
    $statusCode,
    round($executionTime),
    $clientIp
);

// Return response
http_response_code($statusCode);
echo json_encode($response, JSON_PRETTY_PRINT);

// Close any open database connections
Database::closeConnections(); 