<?php

/**
 * CloudXM Plugins Distribution Server
 * Hosted on Hostinger - PHP-based plugin repository
 *
 * This script serves as a WordPress plugin repository, providing:
 * - Plugin catalog (plugins.json)
 * - Individual plugin downloads
 * - Update information (latest.json)
 * - Authentication protection for uploads
 */

// Configuration
define('CLOUDXM_AUTH_TOKEN', getenv('CLOUDXM_AUTH_TOKEN') ?: 'LCcp6PM9FgPia4Lvk6Zg-oerhv@321-984736-dsas223-AADF2');
define('MAX_FILE_SIZE', 50 * 1024 * 1024); // 50MB max
define('ALLOWED_EXTENSIONS', ['zip', 'json']);

// Detect deployment environment from URL path or query parameter
function getDeploymentEnvironment()
{
    // Check query parameter first (from .htaccess rewrite)
    if (isset($_GET['env']) && ($_GET['env'] === 'stable' || $_GET['env'] === 'dev')) {
        return $_GET['env'];
    }

    // Fallback to URL path detection
    $requestUri = $_SERVER['REQUEST_URI'];
    $pathParts = explode('/', trim($requestUri, '/'));

    if (isset($pathParts[0]) && ($pathParts[0] === 'stable' || $pathParts[0] === 'dev')) {
        return $pathParts[0];
    }

    return 'stable'; // Default for root access
}

$environment = getDeploymentEnvironment();
define('DEPLOYMENT_SUBDIR', $environment === 'production' ? '' : $environment);
define('UPLOAD_DIR', __DIR__.'/'.(DEPLOYMENT_SUBDIR ? DEPLOYMENT_SUBDIR.'/' : '').'plugins/');

// Ensure upload directory exists
if (! is_dir(UPLOAD_DIR)) {
    mkdir(UPLOAD_DIR, 0755, true);
}

/**
 * Send JSON response
 */
function sendJsonResponse($data, $statusCode = 200)
{
    http_response_code($statusCode);
    header('Content-Type: application/json');
    header('Access-Control-Allow-Origin: *');
    header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
    header('Access-Control-Allow-Headers: Content-Type, Authorization, X-CloudXM-Auth');
    echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
    exit;
}

/**
 * Send HTML response
 */
function sendHtmlResponse($html, $statusCode = 200)
{
    http_response_code($statusCode);
    header('Content-Type: text/html; charset=UTF-8');
    header('Cache-Control: public, max-age=300');
    echo $html;
    exit;
}

/**
 * Get HTML template for plugin catalog
 */
function getHtmlTemplate()
{
    $environment = DEPLOYMENT_SUBDIR ? ucfirst(DEPLOYMENT_SUBDIR) : 'Production';
    $environmentClass = DEPLOYMENT_SUBDIR ?: 'production';
    $pluginsUrl = DEPLOYMENT_SUBDIR ? '/'.DEPLOYMENT_SUBDIR.'/plugins' : '/plugins';

    // Read template file
    $templatePath = __DIR__.'/template.html';
    if (! file_exists($templatePath)) {
        // Fallback if template file doesn't exist
        return '<!DOCTYPE html><html><head><title>Error</title></head><body><h1>Template file not found</h1></body></html>';
    }

    $template = file_get_contents($templatePath);

    // Replace placeholders
    $template = str_replace('{{ENVIRONMENT}}', $environment, $template);
    $template = str_replace('{{ENVIRONMENT_CLASS}}', $environmentClass, $template);
    $template = str_replace('{{PLUGINS_URL}}', $pluginsUrl, $template);
    $template = str_replace('{{CURRENT_YEAR}}', date('Y'), $template);

    return $template;
}

/**
 * Send file download
 */
function sendFileDownload($filePath, $filename)
{
    if (! file_exists($filePath)) {
        http_response_code(404);
        exit('File not found');
    }

    $mimeType = mime_content_type($filePath);
    header('Content-Type: '.$mimeType);
    header('Content-Disposition: attachment; filename="'.$filename.'"');
    header('Content-Length: '.filesize($filePath));
    header('Cache-Control: public, max-age=3600');
    readfile($filePath);
    exit;
}

/**
 * Validate authentication token
 */
function validateAuthToken()
{
    $authHeader = $_SERVER['HTTP_X_CLOUDXM_AUTH'] ?? '';
    $bearerToken = '';

    // Check Bearer token
    if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
        if (preg_match('/Bearer\s+(.*)$/i', $_SERVER['HTTP_AUTHORIZATION'], $matches)) {
            $bearerToken = $matches[1];
        }
    }

    $token = $authHeader ?: $bearerToken;

    if (empty($token) || $token !== CLOUDXM_AUTH_TOKEN) {
        sendJsonResponse(['error' => 'Unauthorized', 'message' => 'Invalid or missing authentication token'], 401);
    }

    return true;
}

/**
 * Extract screenshots from a plugin ZIP file into the plugin directory.
 * Screenshots are expected at: {plugin-folder}/screenshots/*.{png,jpg,jpeg,webp,gif}
 */
function extractScreenshotsFromZip($zipPath, $pluginDir)
{
    if (! class_exists('ZipArchive') || ! file_exists($zipPath)) {
        return [];
    }

    $zip = new ZipArchive;
    if ($zip->open($zipPath) !== true) {
        return [];
    }

    $screenshotsDir = $pluginDir.'screenshots/';
    $extracted = [];

    for ($i = 0; $i < $zip->numFiles; $i++) {
        $name = $zip->getNameIndex($i);

        // Match: {any-folder}/screenshots/{filename}.{ext}
        if (! preg_match('#^[^/]+/screenshots/([^/]+\.(png|jpg|jpeg|webp|gif))$#i', $name, $m)) {
            continue;
        }

        $filename = $m[1];

        // Skip dotfiles / path traversal attempts
        if (strpos($filename, '..') !== false || strpos($filename, '/') !== false) {
            continue;
        }

        if (! is_dir($screenshotsDir)) {
            mkdir($screenshotsDir, 0755, true);
        }

        $dest = $screenshotsDir.$filename;
        $content = $zip->getFromIndex($i);

        if ($content !== false && file_put_contents($dest, $content) !== false) {
            chmod($dest, 0644);
            $extracted[] = $filename;
        }
    }

    $zip->close();

    return $extracted;
}

/**
 * Get screenshot URLs for a plugin
 */
function getPluginScreenshots($pluginName)
{
    $screenshotsDir = UPLOAD_DIR.$pluginName.'/screenshots/';
    $baseUrl = (isset($_SERVER['HTTPS']) ? 'https://' : 'http://').$_SERVER['HTTP_HOST'];
    if (DEPLOYMENT_SUBDIR) {
        $baseUrl .= '/'.DEPLOYMENT_SUBDIR;
    }

    if (! is_dir($screenshotsDir)) {
        return [];
    }

    $allowed = ['png', 'jpg', 'jpeg', 'webp', 'gif'];
    $files = scandir($screenshotsDir);
    $screenshots = [];

    foreach ($files as $file) {
        if ($file === '.' || $file === '..') {
            continue;
        }
        $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
        if (in_array($ext, $allowed)) {
            $screenshots[] = $baseUrl.'/'.$pluginName.'/screenshots/'.rawurlencode($file);
        }
    }

    sort($screenshots); // alphabetical = numeric order (01-, 02-, ...)

    return $screenshots;
}

/**
 * Upload plugin file
 */
function handlePluginUpload()
{
    validateAuthToken();

    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        sendJsonResponse(['error' => 'Method not allowed'], 405);
    }

    if (! isset($_FILES['plugin'])) {
        sendJsonResponse(['error' => 'No file uploaded'], 400);
    }

    $file = $_FILES['plugin'];
    $pluginName = $_POST['plugin_name'] ?? '';
    $version = $_POST['version'] ?? '';

    // Validate inputs
    if (empty($pluginName) || empty($version)) {
        sendJsonResponse(['error' => 'Missing plugin_name or version'], 400);
    }

    // Validate file
    if ($file['error'] !== UPLOAD_ERR_OK) {
        sendJsonResponse(['error' => 'Upload failed'], 400);
    }

    if ($file['size'] > MAX_FILE_SIZE) {
        sendJsonResponse(['error' => 'File too large'], 400);
    }

    $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
    if (! in_array($extension, ALLOWED_EXTENSIONS)) {
        sendJsonResponse(['error' => 'Invalid file type'], 400);
    }

    // Create plugin directory
    $pluginDir = UPLOAD_DIR.$pluginName.'/';
    if (! is_dir($pluginDir)) {
        mkdir($pluginDir, 0755, true);
    }

    // Handle different file types
    $filename = $file['name'];
    $targetPath = $pluginDir.$filename;

    if (move_uploaded_file($file['tmp_name'], $targetPath)) {
        // Set permissions
        chmod($targetPath, 0644);

        // Extract screenshots from the ZIP
        $screenshots = extractScreenshotsFromZip($targetPath, $pluginDir);

        $response = [
            'success' => true,
            'message' => 'Plugin uploaded successfully',
            'plugin' => $pluginName,
            'version' => $version,
            'file' => $filename,
            'size' => filesize($targetPath),
            'uploaded_at' => date('c'),
            'screenshots_extracted' => count($screenshots),
        ];

        sendJsonResponse($response);
    } else {
        sendJsonResponse(['error' => 'Failed to save file'], 500);
    }
}

/**
 * Get plugins catalog
 */
function getPluginsCatalog()
{
    $plugins = [];
    $pluginsFile = UPLOAD_DIR.'plugins.json';

    if (file_exists($pluginsFile)) {
        $catalogData = json_decode(file_get_contents($pluginsFile), true);
        if (is_array($catalogData) && isset($catalogData['plugins'])) {
            $plugins = $catalogData['plugins'];
        }
    }

    // Add environment info
    $baseUrl = (isset($_SERVER['HTTPS']) ? 'https://' : 'http://').$_SERVER['HTTP_HOST'];
    if (DEPLOYMENT_SUBDIR) {
        $baseUrl .= '/'.DEPLOYMENT_SUBDIR;
    }

    $catalog = [
        'environment' => DEPLOYMENT_SUBDIR ?: 'production',
        'baseUrl' => $baseUrl,
        'generated' => date('c'),
        'plugins' => $plugins,
    ];

    sendJsonResponse($catalog);
}

/**
 * Generate plugin information dynamically
 */
function generatePluginInfo($pluginName)
{
    $pluginDir = UPLOAD_DIR.$pluginName.'/';

    // First, try to get version from catalog
    $catalogFile = UPLOAD_DIR.'plugins.json';
    $catalogVersion = null;

    if (file_exists($catalogFile)) {
        $catalogData = json_decode(file_get_contents($catalogFile), true);
        if (is_array($catalogData) && isset($catalogData['plugins'][$pluginName])) {
            $catalogVersion = $catalogData['plugins'][$pluginName]['currentVersion'] ?? null;
        }
    }

    // Look for ZIP file
    $zipPattern = $pluginDir.'*.zip';
    $zipFiles = glob($zipPattern);

    if (empty($zipFiles)) {
        return false; // No ZIP found
    }

    // If we have catalog version, find the matching ZIP file
    if ($catalogVersion) {
        $expectedFilename = $pluginName.'-v'.$catalogVersion.'.zip';
        foreach ($zipFiles as $zipFile) {
            if (basename($zipFile) === $expectedFilename) {
                $zipFilename = $expectedFilename;
                break;
            }
        }
        $version = $catalogVersion;
    } else {
        // Fallback: use first ZIP file and extract version from filename
        $zipFile = $zipFiles[0];
        $zipFilename = basename($zipFile);

        $version = '1.0.0'; // Default fallback
        if (preg_match('/-v([0-9]+\.[0-9]+\.[0-9]+(?:-[a-zA-Z0-9.-]+)?)\.zip$/', $zipFilename, $matches)) {
            $version = $matches[1];
        }
    }

    // Try to read plugin header from ZIP
    $pluginData = extractPluginMetadata($zipFile);

    // Generate base URL for this environment
    $baseUrl = (isset($_SERVER['HTTPS']) ? 'https://' : 'http://').$_SERVER['HTTP_HOST'];
    if (DEPLOYMENT_SUBDIR) {
        $baseUrl .= '/'.DEPLOYMENT_SUBDIR;
    }

    // Plugin name already includes full name (woocommerce-{plugin-name})
    $pluginSlug = $pluginName;

    // Get all available versions from filesystem
    $versions = [];
    foreach ($zipFiles as $zipFile) {
        $filename = basename($zipFile);
        $ver = '1.0.0'; // Default fallback
        if (preg_match('/-v([0-9]+\.[0-9]+\.[0-9]+(?:-[a-zA-Z0-9.-]+)?)\.zip$/', $filename, $matches)) {
            $ver = $matches[1];
        }
        $versions[] = [
            'version' => $ver,
            'filename' => $filename,
            'download_url' => $baseUrl.'/'.$pluginSlug.'/'.$filename,
            'filesize' => filesize($zipFile),
            'last_modified' => date('c', filemtime($zipFile)),
        ];
    }

    // Sort versions by semantic version (newest first)
    usort($versions, function ($a, $b) {
        return version_compare($b['version'], $a['version']);
    });

    // Use latest version for main info
    $latestVersion = $versions[0] ?? ['version' => $version, 'filename' => $zipFilename];

    // Generate latest.json structure
    $info = [
        'name' => $pluginData['name'] ?? ucwords(str_replace(['-', '_'], ' ', $pluginName)),
        'version' => $latestVersion['version'],
        'download_url' => $latestVersion['download_url'],
        'details_url' => $baseUrl.'/'.$pluginSlug.'/latest.json',
        'requires' => $pluginData['requires'] ?? '5.6',
        'tested' => $pluginData['tested'] ?? '6.5',
        'requires_php' => $pluginData['requires_php'] ?? '7.4',
        'last_updated' => date('Y-m-d'),
        'author' => $pluginData['author'] ?? 'CloudXM',
        'author_profile' => $pluginData['author_profile'] ?? 'https://cloudxm.com.br',
        'homepage' => $pluginData['homepage'] ?? $baseUrl.'/'.$pluginSlug,
        'sections' => [
            'description' => $pluginData['description'] ?? 'CloudXM WordPress Plugin',
            'changelog' => $pluginData['changelog'] ?? 'Latest version with improvements and bug fixes.',
        ],
        'versions' => $versions,
        'screenshots' => getPluginScreenshots($pluginName),
    ];

    return $info;
}

/**
 * Extract plugin metadata from ZIP file
 */
function extractPluginMetadata($zipPath)
{
    $metadata = [];

    if (! file_exists($zipPath)) {
        return $metadata;
    }

    // Check if ZipArchive is available
    if (! class_exists('ZipArchive')) {
        // Fallback: return default metadata without ZIP inspection
        $metadata['name'] = 'CloudXM Plugin';
        $metadata['description'] = 'WordPress plugin for CloudXM ecosystem';
        $metadata['author'] = 'CloudXM';
        $metadata['requires'] = '5.6';
        $metadata['tested'] = '6.5';
        $metadata['requires_php'] = '7.4';

        return $metadata;
    }

    $zip = new ZipArchive;
    if ($zip->open($zipPath) === true) {
        // Find main plugin file (usually plugin-name.php)
        for ($i = 0; $i < $zip->numFiles; $i++) {
            $filename = $zip->getNameIndex($i);

            // Look for main plugin file (not in subdirectories)
            if (preg_match('/^[^\/]+\.php$/', $filename)) {
                $content = $zip->getFromIndex($i);

                // Extract headers
                if (preg_match('/Plugin Name:\s*(.+)$/im', $content, $matches)) {
                    $metadata['name'] = trim($matches[1]);
                }
                if (preg_match('/Description:\s*(.+)$/im', $content, $matches)) {
                    $metadata['description'] = trim($matches[1]);
                }
                if (preg_match('/Author:\s*(.+)$/im', $content, $matches)) {
                    $metadata['author'] = trim($matches[1]);
                }
                if (preg_match('/Requires at least:\s*(.+)$/im', $content, $matches)) {
                    $metadata['requires'] = trim($matches[1]);
                }
                if (preg_match('/Tested up to:\s*(.+)$/im', $content, $matches)) {
                    $metadata['tested'] = trim($matches[1]);
                }
                if (preg_match('/Requires PHP:\s*(.+)$/im', $content, $matches)) {
                    $metadata['requires_php'] = trim($matches[1]);
                }

                break; // Found main plugin file
            }
        }
        $zip->close();
    }

    return $metadata;
}

/**
 * Get plugin information
 */
function getPluginInfo($pluginName)
{
    $info = generatePluginInfo($pluginName);

    if ($info === false) {
        sendJsonResponse(['error' => 'Plugin not found'], 404);
    }

    sendJsonResponse($info);
}

/**
 * Download plugin file
 */
function downloadPlugin($pluginName, $filename)
{
    $pluginDir = UPLOAD_DIR.$pluginName.'/';

    // Handle special "latest" or "vlatest" requests
    if ($filename === 'vlatest.zip' || $filename === 'latest.zip' || $filename === $pluginName.'-vlatest.zip') {
        // Find the latest version ZIP file
        $zipPattern = $pluginDir.'*.zip';
        $zipFiles = glob($zipPattern);

        if (empty($zipFiles)) {
            sendJsonResponse(['error' => 'No plugin files found'], 404);
        }

        // Extract versions and find the latest
        $versionFiles = [];
        foreach ($zipFiles as $zipFile) {
            $basename = basename($zipFile);
            $ver = '1.0.0'; // Default fallback
            if (preg_match('/-v([0-9]+\.[0-9]+\.[0-9]+(?:-[a-zA-Z0-9.-]+)?)\.zip$/', $basename, $matches)) {
                $ver = $matches[1];
            }
            $versionFiles[] = ['version' => $ver, 'filename' => $basename];
        }

        // Sort by version descending
        usort($versionFiles, function ($a, $b) {
            return version_compare($b['version'], $a['version']);
        });

        $filename = $versionFiles[0]['filename'];
    }

    $filePath = $pluginDir.$filename;

    if (! file_exists($filePath)) {
        sendJsonResponse(['error' => 'File not found'], 404);
    }

    // Security check - only allow zip and json files
    $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    if (! in_array($extension, ALLOWED_EXTENSIONS)) {
        sendJsonResponse(['error' => 'Access denied'], 403);
    }

    sendFileDownload($filePath, $filename);
}

/**
 * Register uploaded plugin
 */
function registerUploadedPlugin()
{
    validateAuthToken();

    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        sendJsonResponse(['error' => 'Method not allowed'], 405);
    }

    $input = json_decode(file_get_contents('php://input'), true);
    if (! $input || ! isset($input['plugin_name']) || ! isset($input['version']) || ! isset($input['filename'])) {
        sendJsonResponse(['error' => 'Missing required fields: plugin_name, version, filename'], 400);
    }

    $pluginName = $input['plugin_name'];
    $version = $input['version'];
    $filename = $input['filename'];

    // Verify the plugin file exists
    $pluginDir = UPLOAD_DIR.$pluginName.'/';
    $pluginFile = $pluginDir.$filename;

    if (! file_exists($pluginFile)) {
        sendJsonResponse(['error' => 'Plugin file not found'], 404);
    }

    $catalogFile = UPLOAD_DIR.'plugins.json';

    // Load existing catalog if it exists
    $existingCatalog = [];
    if (file_exists($catalogFile)) {
        $existingCatalog = json_decode(file_get_contents($catalogFile), true) ?: [];
    }

    // Generate base URL for this environment
    $baseUrl = (isset($_SERVER['HTTPS']) ? 'https://' : 'http://').$_SERVER['HTTP_HOST'];
    if (DEPLOYMENT_SUBDIR) {
        $baseUrl .= '/'.DEPLOYMENT_SUBDIR;
    }

    // Create plugin info
    $pluginInfo = [
        'name' => $pluginName,
        'description' => 'CloudXM WordPress Plugin',
        'currentVersion' => $version,
        'downloadUrl' => $baseUrl.'/'.$pluginName.'/'.$filename,
        'distributionUrl' => $baseUrl.'/'.$pluginName.'/',
        'infoUrl' => $baseUrl.'/'.$pluginName.'/latest.json',
    ];

    // Merge with existing plugins
    $existingPlugins = $existingCatalog['plugins'] ?? [];
    $existingPlugins[$pluginName] = $pluginInfo;

    $catalog = [
        'environment' => DEPLOYMENT_SUBDIR ?: 'production',
        'baseUrl' => $baseUrl,
        'generated' => date('c'),
        'plugins' => $existingPlugins,
    ];

    if (file_put_contents($catalogFile, json_encode($catalog, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE))) {
        sendJsonResponse([
            'success' => true,
            'message' => 'Plugin registered successfully',
            'plugin' => $pluginName,
            'version' => $version,
            'updated_at' => $catalog['generated'],
            'plugins_count' => count($existingPlugins),
        ]);
    } else {
        sendJsonResponse(['error' => 'Failed to update catalog'], 500);
    }
}

/**
 * Update plugins catalog (legacy - kept for backward compatibility)
 */
function updatePluginsCatalog()
{
    validateAuthToken();

    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        sendJsonResponse(['error' => 'Method not allowed'], 405);
    }

    $input = json_decode(file_get_contents('php://input'), true);
    if (! $input || ! isset($input['plugins'])) {
        sendJsonResponse(['error' => 'Invalid JSON data'], 400);
    }

    $catalogFile = UPLOAD_DIR.'plugins.json';

    // Load existing catalog if it exists
    $existingCatalog = [];
    if (file_exists($catalogFile)) {
        $existingCatalog = json_decode(file_get_contents($catalogFile), true) ?: [];
    }

    // Merge plugins - new plugins override existing ones with same name
    $existingPlugins = $existingCatalog['plugins'] ?? [];
    $newPlugins = $input['plugins'] ?? [];
    $mergedPlugins = array_merge($existingPlugins, $newPlugins);

    // Add metadata
    $defaultBaseUrl = (isset($_SERVER['HTTPS']) ? 'https://' : 'http://').$_SERVER['HTTP_HOST'];
    if (DEPLOYMENT_SUBDIR) {
        $defaultBaseUrl .= '/'.DEPLOYMENT_SUBDIR;
    }

    $catalog = [
        'environment' => DEPLOYMENT_SUBDIR ?: ($input['environment'] ?? 'production'),
        'baseUrl' => $input['baseUrl'] ?? $defaultBaseUrl,
        'generated' => date('c'),
        'plugins' => $mergedPlugins,
    ];

    if (file_put_contents($catalogFile, json_encode($catalog, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE))) {
        sendJsonResponse([
            'success' => true,
            'message' => 'Catalog updated successfully',
            'updated_at' => $catalog['generated'],
            'plugins_count' => count($mergedPlugins),
        ]);
    } else {
        sendJsonResponse(['error' => 'Failed to update catalog'], 500);
    }
}

/**
 * Show plugin details page
 */
function showPluginDetailsPage($pluginName)
{
    $pluginInfo = generatePluginInfo($pluginName);

    if ($pluginInfo === false) {
        sendJsonResponse(['error' => 'Plugin not found'], 404);
    }

    // Generate base URL for this environment
    $baseUrl = (isset($_SERVER['HTTPS']) ? 'https://' : 'http://').$_SERVER['HTTP_HOST'];
    if (DEPLOYMENT_SUBDIR) {
        $baseUrl .= '/'.DEPLOYMENT_SUBDIR;
    }

    $pluginSlug = $pluginName;

    // Generate root URL for static assets
    $rootUrl = (isset($_SERVER['HTTPS']) ? 'https://' : 'http://').$_SERVER['HTTP_HOST'];

    // Create HTML page
    $html = '<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>'.htmlspecialchars($pluginInfo['name']).' - CloudXM Plugins</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        /* Lightbox styles */
        .lightbox {
            display: none;
            position: fixed;
            z-index: 9999;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.9);
            justify-content: center;
            align-items: center;
        }
        .lightbox.active {
            display: flex;
        }
        .lightbox-content {
            max-width: 90%;
            max-height: 90%;
            object-fit: contain;
        }
        .lightbox-close {
            position: absolute;
            top: 20px;
            right: 30px;
            color: #fff;
            font-size: 40px;
            cursor: pointer;
            user-select: none;
        }
        .lightbox-nav {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            color: #fff;
            font-size: 50px;
            cursor: pointer;
            user-select: none;
            padding: 20px;
            transition: color 0.2s;
        }
        .lightbox-nav:hover {
            color: #3b82f6;
        }
        .lightbox-prev {
            left: 20px;
        }
        .lightbox-next {
            right: 20px;
        }
        .lightbox-counter {
            position: absolute;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            color: #fff;
            font-size: 16px;
        }
    </style>
</head>
<body class="bg-gray-50 min-h-screen">
    <div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-8 lg:py-12">

        <div class="mb-8">
            <a href="'.$baseUrl.'" class="text-blue-600 hover:text-blue-800 text-sm font-medium inline-flex items-center gap-1">
                <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path></svg>
                Back to Plugin Catalog
            </a>
        </div>

        <div class="max-w-3xl mx-auto">
            <div class="bg-white rounded-2xl shadow-lg border border-gray-100 p-8 lg:p-10">
                <header class="text-center mb-8">
                    <div class="w-20 h-20 bg-gradient-to-br from-purple-600 to-indigo-700 rounded-2xl flex items-center justify-center mx-auto mb-4">
                        <span class="text-3xl font-bold text-white">'.strtoupper(mb_substr($pluginInfo['name'], 0, 1)).'</span>
                    </div>
                    <h1 class="text-2xl lg:text-3xl font-bold text-gray-900 mb-2">'.htmlspecialchars($pluginInfo['name']).'</h1>
                    <p class="text-gray-600">'.htmlspecialchars($pluginInfo['sections']['description']).'</p>
                </header>

                <div class="bg-gray-50 rounded-xl p-6 mb-8">
                    <div class="grid sm:grid-cols-2 gap-4 text-sm">
                        <div>
                            <span class="block text-gray-500 mb-1">Version</span>
                            <span class="font-medium text-gray-900">'.htmlspecialchars($pluginInfo['version']).'</span>
                        </div>
                        <div>
                            <span class="block text-gray-500 mb-1">Author</span>
                            <a href="'.htmlspecialchars($pluginInfo['author_profile']).'" class="font-medium text-blue-600 hover:text-blue-800">'.htmlspecialchars($pluginInfo['author']).'</a>
                        </div>
                        <div>
                            <span class="block text-gray-500 mb-1">Last Updated</span>
                            <span class="font-medium text-gray-900">'.htmlspecialchars($pluginInfo['last_updated']).'</span>
                        </div>
                        <div>
                            <span class="block text-gray-500 mb-1">Requires WordPress</span>
                            <span class="font-medium text-gray-900">'.htmlspecialchars($pluginInfo['requires']).'</span>
                        </div>
                        <div>
                            <span class="block text-gray-500 mb-1">Tested up to</span>
                            <span class="font-medium text-gray-900">'.htmlspecialchars($pluginInfo['tested']).'</span>
                        </div>
                        <div>
                            <span class="block text-gray-500 mb-1">Requires PHP</span>
                            <span class="font-medium text-gray-900">'.htmlspecialchars($pluginInfo['requires_php']).'</span>
                        </div>
                    </div>
                </div>

                <div class="flex flex-col sm:flex-row gap-3 justify-center">
                    <a href="'.htmlspecialchars($pluginInfo['download_url']).'" download
                       class="inline-flex items-center justify-center gap-2 bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2.5 px-5 rounded-lg transition duration-200 shadow-md hover:shadow-lg">
                        <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg>
                        Download ZIP ('.htmlspecialchars($pluginInfo['version']).')
                    </a>
                    <a href="'.htmlspecialchars($pluginInfo['details_url']).'"
                       class="inline-flex items-center justify-center gap-2 bg-gray-100 hover:bg-gray-200 text-gray-700 font-semibold py-2.5 px-5 rounded-lg transition duration-200">
                        <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"></path></svg>
                        View Update Info (JSON)
                    </a>
                </div>

                <div class="mt-8">
                    <h2 class="text-lg font-semibold text-gray-800 mb-3">Changelog</h2>
                    <p class="text-sm text-gray-600 leading-relaxed">'.nl2br(htmlspecialchars($pluginInfo['sections']['changelog'])).'</p>
                </div>
            </div>
        </div>

    </div>';

    // Screenshots section (outside the card, full-width feel)
    if (! empty($pluginInfo['screenshots'])) {
        $screenshotsData = json_encode($pluginInfo['screenshots']);
        $screenshotsHtml = '';
        foreach ($pluginInfo['screenshots'] as $i => $url) {
            $num = $i + 1;
            $screenshotsHtml .= '
                <div class="flex-shrink-0">
                    <a href="'.htmlspecialchars($url).'" data-screenshot-index="'.$i.'" class="block group screenshot-link">
                        <img src="'.htmlspecialchars($url).'"
                             alt="Screenshot '.$num.'"
                             loading="lazy"
                             class="rounded-xl border border-gray-200 shadow-md group-hover:shadow-xl group-hover:scale-105 transition-all duration-200 max-h-64 w-auto object-cover cursor-pointer">
                        <p class="text-xs text-center text-gray-400 mt-1">Click to enlarge</p>
                    </a>
                </div>';
        }

        $html .= '
    <div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 mt-10 mb-4">
        <h2 class="text-xl font-semibold text-gray-800 mb-5">Screenshots</h2>
        <div class="flex flex-wrap gap-5 justify-center">
            '.$screenshotsHtml.'
        </div>
    </div>

    <!-- Lightbox modal -->
    <div id="lightbox" class="lightbox">
        <span class="lightbox-close">&times;</span>
        <span class="lightbox-nav lightbox-prev">&#10094;</span>
        <img src="" alt="" class="lightbox-content" id="lightbox-img">
        <span class="lightbox-nav lightbox-next">&#10095;</span>
        <div class="lightbox-counter" id="lightbox-counter"></div>
    </div>

    <script>
        (function() {
            var screenshots = '.$screenshotsData.';
            var lightbox = document.getElementById("lightbox");
            var lightboxImg = document.getElementById("lightbox-img");
            var lightboxCounter = document.getElementById("lightbox-counter");
            var currentIndex = 0;

            function openLightbox(index) {
                currentIndex = index;
                updateLightboxImage();
                lightbox.classList.add("active");
                document.body.style.overflow = "hidden";
            }

            function updateLightboxImage() {
                lightboxImg.src = screenshots[currentIndex];
                lightboxCounter.textContent = (currentIndex + 1) + " / " + screenshots.length;
            }

            function closeLightbox() {
                lightbox.classList.remove("active");
                document.body.style.overflow = "";
            }

            function nextImage() {
                currentIndex = (currentIndex + 1) % screenshots.length;
                updateLightboxImage();
            }

            function prevImage() {
                currentIndex = (currentIndex - 1 + screenshots.length) % screenshots.length;
                updateLightboxImage();
            }

            // Add click handlers to screenshot links
            document.querySelectorAll(".screenshot-link").forEach(function(link) {
                link.addEventListener("click", function(e) {
                    e.preventDefault();
                    openLightbox(parseInt(this.getAttribute("data-screenshot-index")));
                });
            });

            // Close button
            lightbox.querySelector(".lightbox-close").addEventListener("click", closeLightbox);

            // Navigation buttons
            lightbox.querySelector(".lightbox-next").addEventListener("click", nextImage);
            lightbox.querySelector(".lightbox-prev").addEventListener("click", prevImage);

            // Click outside image to close
            lightbox.addEventListener("click", function(e) {
                if (e.target === lightbox) {
                    closeLightbox();
                }
            });

            // Keyboard navigation
            document.addEventListener("keydown", function(e) {
                if (!lightbox.classList.contains("active")) return;

                if (e.key === "Escape") {
                    closeLightbox();
                } else if (e.key === "ArrowRight") {
                    nextImage();
                } else if (e.key === "ArrowLeft") {
                    prevImage();
                }
            });
        })();
    </script>';
    }

    $html .= '
    <footer class="mt-16 pt-8 border-t border-gray-200">
        <div class="max-w-5xl mx-auto text-center text-sm text-gray-600">
            <p>&copy; '.date('Y').' CloudXM. Plugins for automated electronic invoice emission.</p>
        </div>
    </footer>
</body>
</html>';

    sendHtmlResponse($html);
}

/**
 * Health check
 */
function healthCheck()
{
    $health = [
        'status' => 'healthy',
        'timestamp' => date('c'),
        'version' => '1.0.0',
        'upload_dir' => is_writable(UPLOAD_DIR) ? 'writable' : 'not writable',
        'plugins_count' => count(glob(UPLOAD_DIR.'*/latest.json')),
    ];

    sendJsonResponse($health);
}

// Handle CORS preflight
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    header('Access-Control-Allow-Origin: *');
    header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
    header('Access-Control-Allow-Headers: Content-Type, Authorization, X-CloudXM-Auth');
    exit;
}

// Routing
$requestUri = $_SERVER['REQUEST_URI'];
$path = parse_url($requestUri, PHP_URL_PATH);
$path = ltrim($path, '/');

// Check if we have a path parameter from .htaccess rewrite
if (isset($_GET['path'])) {
    $path = $_GET['path'];
} else {
    // Strip environment prefix from path for routing
    $pathParts = explode('/', $path);
    if (isset($pathParts[0]) && ($pathParts[0] === 'stable' || $pathParts[0] === 'dev')) {
        array_shift($pathParts); // Remove environment from path
        $path = implode('/', $pathParts);
    } else {
        $path = implode('/', $pathParts);
    }
}

// Remove script name from path if running as index.php
if (basename($_SERVER['SCRIPT_NAME']) === 'index.php') {
    $scriptPath = dirname($_SERVER['SCRIPT_NAME']);
    if ($scriptPath !== '/' && strpos($path, ltrim($scriptPath, '/')) === 0) {
        $path = substr($path, strlen(ltrim($scriptPath, '/')) + 1);
    }
}

$pathParts = explode('/', $path);
$method = $_SERVER['REQUEST_METHOD'];

try {
    // Check if client wants HTML (browser request to root)
    $acceptHeader = $_SERVER['HTTP_ACCEPT'] ?? '';
    $wantsHtml = strpos($acceptHeader, 'text/html') !== false;

    switch ($pathParts[0]) {
        case '':
            if ($method === 'GET' && $wantsHtml) {
                // GET / - Serve beautiful HTML interface for browsers
                sendHtmlResponse(getHtmlTemplate());
            } else {
                // GET / - API request, return JSON
                getPluginsCatalog();
            }
            break;

        case 'plugins':
            if ($method === 'GET') {
                if (count($pathParts) === 1 || (count($pathParts) === 2 && empty($pathParts[1]))) {
                    // GET /plugins - API request, return JSON
                    getPluginsCatalog();
                } elseif (count($pathParts) === 2 && $pathParts[1] === 'catalog') {
                    // GET /plugins/catalog
                    getPluginsCatalog();
                } elseif (count($pathParts) === 2 && $pathParts[1] === 'plugins.json') {
                    // GET /plugins/plugins.json - Direct access to catalog file
                    getPluginsCatalog();
                }
            } elseif ($method === 'POST' && count($pathParts) === 2 && ($pathParts[1] === 'catalog' || $pathParts[1] === 'catalog/')) {
                // POST /plugins/catalog
                updatePluginsCatalog();
            } elseif ($method === 'POST' && count($pathParts) === 2 && ($pathParts[1] === 'upload' || $pathParts[1] === 'upload/')) {
                // POST /plugins/upload
                handlePluginUpload();
            } elseif ($method === 'POST' && count($pathParts) === 2 && ($pathParts[1] === 'uploaded' || $pathParts[1] === 'uploaded/')) {
                // POST /plugins/uploaded
                registerUploadedPlugin();
            }
            break;

        default:
            // Handle woocommerce-{plugin-name}/latest.json and file downloads
            if (count($pathParts) >= 1 && strpos($pathParts[0], 'woocommerce-') === 0) {
                $pluginSlug = $pathParts[0]; // e.g., "woocommerce-cloudxm-marlim"
                $pluginName = $pluginSlug; // Use full plugin name including woocommerce- prefix

                if (count($pathParts) === 1 || (count($pathParts) === 2 && empty($pathParts[1]))) {
                    // GET /woocommerce-{plugin-name}/ - Show plugin details page
                    showPluginDetailsPage($pluginName);
                } elseif (count($pathParts) === 2 && $pathParts[1] === 'latest.json') {
                    // GET /woocommerce-{plugin-name}/latest.json
                    getPluginInfo($pluginName);
                } elseif (count($pathParts) === 2) {
                    // GET /woocommerce-{plugin-name}/{filename}
                    $filename = $pathParts[1];
                    downloadPlugin($pluginName, $filename);
                } elseif (count($pathParts) === 3 && $pathParts[1] === 'screenshots') {
                    // GET /woocommerce-{plugin-name}/screenshots/{image}
                    $imageFile = $pathParts[2];
                    $imagePath = UPLOAD_DIR.$pluginName.'/screenshots/'.$imageFile;

                    // Security: only allow image files, no path traversal
                    if (strpos($imageFile, '..') !== false || strpos($imageFile, '/') !== false) {
                        sendJsonResponse(['error' => 'Access denied'], 403);
                    }

                    $allowedImageExts = ['png', 'jpg', 'jpeg', 'webp', 'gif'];
                    $ext = strtolower(pathinfo($imageFile, PATHINFO_EXTENSION));
                    if (! in_array($ext, $allowedImageExts)) {
                        sendJsonResponse(['error' => 'Access denied'], 403);
                    }

                    if (! file_exists($imagePath)) {
                        sendJsonResponse(['error' => 'Image not found'], 404);
                    }

                    $mimeTypes = [
                        'png' => 'image/png',
                        'jpg' => 'image/jpeg',
                        'jpeg' => 'image/jpeg',
                        'webp' => 'image/webp',
                        'gif' => 'image/gif',
                    ];
                    header('Content-Type: '.$mimeTypes[$ext]);
                    header('Content-Length: '.filesize($imagePath));
                    header('Cache-Control: public, max-age=86400');
                    readfile($imagePath);
                    exit;
                } else {
                    // Handle deeper paths
                    $filename = implode('/', array_slice($pathParts, 1));
                    downloadPlugin($pluginName, $filename);
                }
            }
            // Legacy support for /plugin/ routes
            elseif ($pathParts[0] === 'plugin' && count($pathParts) >= 2) {
                $pluginName = $pathParts[1];
                if (count($pathParts) === 2) {
                    // GET /plugin/{name}
                    getPluginInfo($pluginName);
                } elseif (count($pathParts) === 3) {
                    // GET /plugin/{name}/{filename}
                    $filename = $pathParts[2];
                    downloadPlugin($pluginName, $filename);
                }
            } elseif ($pathParts[0] === 'health' && $method === 'GET') {
                healthCheck();
            } else {
                // Try to serve plugin files directly (fallback)
                if (count($pathParts) >= 2) {
                    $potentialPlugin = $pathParts[0];
                    $filename = implode('/', array_slice($pathParts, 1));
                    downloadPlugin($potentialPlugin, $filename);
                }
            }
            break;
    }

    // If no route matched, return 404
    sendJsonResponse(['error' => 'Not found'], 404);

} catch (Exception $e) {
    error_log('CloudXM Plugin Server Error: '.$e->getMessage());
    sendJsonResponse(['error' => 'Internal server error'], 500);
}
