<?php
/**
 * API Response Helper Functions
 * Provides standardized API responses across EasyStream
 */

if (!defined('_ISVALID')) {
    die('Direct access is not allowed');
}

/**
 * Send success response
 * Standardized success response format for all API endpoints
 *
 * @param mixed $data Data to return (can be array, object, string, etc.)
 * @param int $statusCode HTTP status code (default: 200)
 * @param array $meta Optional metadata (pagination, etc.)
 * @return void (exits after sending response)
 */
function sendApiSuccess($data = null, $statusCode = 200, $meta = null) {
    http_response_code($statusCode);
    header('Content-Type: application/json; charset=utf-8');

    $response = [
        'success' => true,
        'data' => $data,
        'error' => null
    ];

    // Add metadata if provided (pagination, etc.)
    if ($meta !== null) {
        $response['meta'] = $meta;
    }

    // Add timestamp
    $response['timestamp'] = date('Y-m-d H:i:s');

    echo json_encode($response, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

    exit;
}

/**
 * Send error response
 * Standardized error response format for all API endpoints
 *
 * @param string $message Error message
 * @param int $statusCode HTTP status code (default: 400)
 * @param array $details Additional error details (validation errors, etc.)
 * @return void (exits after sending response)
 */
function sendApiError($message, $statusCode = 400, $details = null) {
    http_response_code($statusCode);
    header('Content-Type: application/json; charset=utf-8');

    $response = [
        'success' => false,
        'data' => null,
        'error' => $message
    ];

    // Add error details if provided
    if ($details !== null) {
        $response['details'] = $details;
    }

    // Add timestamp
    $response['timestamp'] = date('Y-m-d H:i:s');

    // Log error for debugging
    VLogger::log('error', 'API Error: ' . $message, [
        'status_code' => $statusCode,
        'details' => $details,
        'endpoint' => $_SERVER['REQUEST_URI'] ?? 'unknown',
        'method' => $_SERVER['REQUEST_METHOD'] ?? 'unknown'
    ]);

    echo json_encode($response, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

    exit;
}

/**
 * Validate API request method
 * Ensures only allowed HTTP methods are used
 *
 * @param string|array $allowedMethods Single method or array of allowed methods
 * @throws Exception if method not allowed (sends 405 response)
 * @return void
 */
function validateApiMethod($allowedMethods) {
    $allowedMethods = (array) $allowedMethods;
    $currentMethod = $_SERVER['REQUEST_METHOD'];

    if (!in_array($currentMethod, $allowedMethods)) {
        sendApiError(
            'Method not allowed. Allowed methods: ' . implode(', ', $allowedMethods),
            405,
            ['allowed_methods' => $allowedMethods, 'current_method' => $currentMethod]
        );
    }
}

/**
 * Get JSON input from request body
 * Handles both JSON and form-encoded data
 *
 * @param bool $assoc Return as associative array (default: true)
 * @return array|object Decoded JSON data
 * @throws Exception if JSON is invalid
 */
function getJsonInput($assoc = true) {
    $input = file_get_contents('php://input');

    if (empty($input)) {
        return $assoc ? [] : (object) [];
    }

    $data = json_decode($input, $assoc);

    if (json_last_error() !== JSON_ERROR_NONE) {
        sendApiError(
            'Invalid JSON input: ' . json_last_error_msg(),
            400,
            ['json_error' => json_last_error_msg()]
        );
    }

    return $data;
}

/**
 * Validate required fields in request data
 * Checks if all required fields are present and not empty
 *
 * @param array $data Request data
 * @param array $requiredFields Array of required field names
 * @return void (sends error response if validation fails)
 */
function validateRequiredFields($data, $requiredFields) {
    $missingFields = [];

    foreach ($requiredFields as $field) {
        if (!isset($data[$field]) || (is_string($data[$field]) && trim($data[$field]) === '')) {
            $missingFields[] = $field;
        }
    }

    if (!empty($missingFields)) {
        sendApiError(
            'Missing required fields',
            400,
            ['missing_fields' => $missingFields, 'required_fields' => $requiredFields]
        );
    }
}

/**
 * Get pagination parameters from request
 * Standardized pagination handling
 *
 * @param int $defaultLimit Default items per page (default: 20)
 * @param int $maxLimit Maximum items per page (default: 100)
 * @return array ['page', 'limit', 'offset']
 */
function getPaginationParams($defaultLimit = 20, $maxLimit = 100) {
    $page = isset($_GET['page']) ? max(1, (int) $_GET['page']) : 1;
    $limit = isset($_GET['limit']) ? min($maxLimit, max(1, (int) $_GET['limit'])) : $defaultLimit;
    $offset = ($page - 1) * $limit;

    return [
        'page' => $page,
        'limit' => $limit,
        'offset' => $offset
    ];
}

/**
 * Create pagination metadata
 * Returns standardized pagination info for responses
 *
 * @param int $page Current page
 * @param int $limit Items per page
 * @param int $total Total items
 * @return array Pagination metadata
 */
function createPaginationMeta($page, $limit, $total) {
    return [
        'page' => $page,
        'limit' => $limit,
        'total' => $total,
        'pages' => ceil($total / $limit),
        'has_more' => $page < ceil($total / $limit)
    ];
}

/**
 * Require authentication for API endpoint
 * Checks if user is authenticated via JWT or session
 *
 * @return int User ID
 * @throws Exception if not authenticated (sends 401 response)
 */
function requireAuth() {
    $userId = null;

    // Try JWT authentication first
    $authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? null;

    if ($authHeader && preg_match('/Bearer\s+(.*)$/i', $authHeader, $matches)) {
        $token = $matches[1];
        $tokenData = VAuth::verifyToken($token);

        if ($tokenData && isset($tokenData['user_id'])) {
            $userId = $tokenData['user_id'];
        }
    }

    // Fall back to session authentication
    if (!$userId) {
        $userId = getCurrentUserId();
    }

    if (!$userId) {
        sendApiError('Authentication required', 401);
    }

    return $userId;
}

/**
 * Check user permission for API endpoint
 * Requires authentication and checks RBAC permission
 *
 * @param string $permission Permission to check (e.g., 'videos.delete')
 * @return int User ID if authorized
 * @throws Exception if not authorized (sends 403 response)
 */
function requirePermission($permission) {
    $userId = requireAuth();

    if (!VAuth::hasPermission($permission)) {
        sendApiError(
            'Permission denied',
            403,
            ['required_permission' => $permission, 'user_id' => $userId]
        );
    }

    return $userId;
}

/**
 * Rate limit API requests
 * Simple in-memory rate limiting (consider Redis for production)
 *
 * @param string $key Rate limit key (e.g., 'api:' . $userId)
 * @param int $maxRequests Maximum requests allowed
 * @param int $timeWindow Time window in seconds
 * @return void (sends 429 response if limit exceeded)
 */
function rateLimitApiRequest($key, $maxRequests = 60, $timeWindow = 60) {
    // Use APCu if available, otherwise session
    if (function_exists('apcu_fetch')) {
        $requests = apcu_fetch($key, $success);

        if (!$success) {
            $requests = ['count' => 0, 'start' => time()];
        }

        // Reset if time window expired
        if (time() - $requests['start'] > $timeWindow) {
            $requests = ['count' => 0, 'start' => time()];
        }

        $requests['count']++;

        if ($requests['count'] > $maxRequests) {
            $retryAfter = $timeWindow - (time() - $requests['start']);

            header('Retry-After: ' . $retryAfter);
            header('X-RateLimit-Limit: ' . $maxRequests);
            header('X-RateLimit-Remaining: 0');
            header('X-RateLimit-Reset: ' . ($requests['start'] + $timeWindow));

            sendApiError(
                'Rate limit exceeded',
                429,
                [
                    'max_requests' => $maxRequests,
                    'time_window' => $timeWindow,
                    'retry_after' => $retryAfter
                ]
            );
        }

        apcu_store($key, $requests, $timeWindow);

        // Add rate limit headers
        header('X-RateLimit-Limit: ' . $maxRequests);
        header('X-RateLimit-Remaining: ' . ($maxRequests - $requests['count']));
        header('X-RateLimit-Reset: ' . ($requests['start'] + $timeWindow));

    } else {
        // Fallback: Use session storage (not ideal for distributed systems)
        if (!isset($_SESSION['rate_limit'])) {
            $_SESSION['rate_limit'] = [];
        }

        if (!isset($_SESSION['rate_limit'][$key])) {
            $_SESSION['rate_limit'][$key] = ['count' => 0, 'start' => time()];
        }

        $requests = $_SESSION['rate_limit'][$key];

        // Reset if time window expired
        if (time() - $requests['start'] > $timeWindow) {
            $_SESSION['rate_limit'][$key] = ['count' => 0, 'start' => time()];
            $requests = $_SESSION['rate_limit'][$key];
        }

        $requests['count']++;
        $_SESSION['rate_limit'][$key] = $requests;

        if ($requests['count'] > $maxRequests) {
            $retryAfter = $timeWindow - (time() - $requests['start']);

            header('Retry-After: ' . $retryAfter);

            sendApiError(
                'Rate limit exceeded',
                429,
                [
                    'max_requests' => $maxRequests,
                    'time_window' => $timeWindow,
                    'retry_after' => $retryAfter
                ]
            );
        }
    }
}

/**
 * Sanitize API input
 * Wrapper around VSecurity::sanitize with logging
 *
 * @param mixed $input Input to sanitize
 * @param string $type Type of sanitization (string, email, url, int, etc.)
 * @return mixed Sanitized input
 */
function sanitizeApiInput($input, $type = 'string') {
    if ($input === null) {
        return null;
    }

    switch ($type) {
        case 'int':
            return (int) $input;

        case 'float':
            return (float) $input;

        case 'bool':
            return (bool) $input;

        case 'email':
            return filter_var($input, FILTER_SANITIZE_EMAIL);

        case 'url':
            return filter_var($input, FILTER_SANITIZE_URL);

        case 'string':
        default:
            return VSecurity::sanitize($input);
    }
}

/**
 * Log API request for debugging/analytics
 *
 * @param string $endpoint Endpoint name
 * @param array $data Additional data to log
 * @return void
 */
function logApiRequest($endpoint, $data = []) {
    VLogger::log('info', 'API Request', array_merge([
        'endpoint' => $endpoint,
        'method' => $_SERVER['REQUEST_METHOD'] ?? 'unknown',
        'user_id' => getCurrentUserId(),
        'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
        'user_agent' => substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 200)
    ], $data));
}
