<?php
/**
 * Main entry point - handles download or device setup
 */
function main() {
    if (isset($_GET['name'])) {
        handleDownload();
    } else {
        handleDeviceSetup();
    }
}

/**
 * Handles file downloads based on name parameter
 */
function handleDownload() {
    // Sanitize inputs
    $name = isset($_GET['name']) ? $_GET['name'] : '';
    $GUID = isset($_GET['GUID']) ? preg_replace('/[^a-zA-Z0-9\-]/', '', $_GET['GUID']) : '';
    $variant = isset($_GET['variant']) ? $_GET['variant'] : '';
    
    // Validate GUID
    if (empty($GUID)) {
        header("HTTP/1.0 400 Bad Request");
        exit('Error: GUID is required');
    }
    
    // Use relative paths from the script's directory
    $baseDir = __DIR__;
    $deviceDir = $baseDir . "/device/$GUID/";
    
    // Check if device directory exists
    if (!is_dir($deviceDir)) {
        header("HTTP/1.0 404 Not Found");
        exit('Error: Device not found. Please run setup first.');
    }
    
    // Read ProductType and iOS from saved files
    $productTypeFile = $deviceDir . 'ProductType.txt';
    $iOSFile = $deviceDir . 'iOS.txt';
    
    if (!file_exists($productTypeFile) || !file_exists($iOSFile)) {
        header("HTTP/1.0 404 Not Found");
        exit('Error: Device info not found. Please run setup first.');
    }
    
    $ProductType = trim(file_get_contents($productTypeFile));
    $iOS = trim(file_get_contents($iOSFile));
    
    // Apply variant suffix to ProductType if needed
    if ($variant === 'china') {
        $ProductType .= '_CH';
    }
    
    // Set up paths - use the stored iOS path directly
    $modelDir = $baseDir . "/files/model/$ProductType/$iOS/";
    
    // Determine which file to download
    $filePath = '';
    $fileName = '';
    
    switch ($name) {
        case 'epub':
            $filePath = $modelDir . 'asset3.epub';
            $fileName = 'asset3.epub';
            break;
            
        case 'sqlite':
            $filePath = $deviceDir . 'BLDatabaseManager.sqlite';
            $fileName = 'BLDatabaseManager.sqlite';
            break;
            
        case 'sqlite-shm':
            $filePath = $baseDir . '/files/common/BLDatabaseManager.sqlite-shm';
            $fileName = 'BLDatabaseManager.sqlite-shm';
            break;
            
        case 'sqlite-wal':
            $filePath = $baseDir . '/files/common/BLDatabaseManager.sqlite-wal';
            $fileName = 'BLDatabaseManager.sqlite-wal';
            break;
            
        case 'plist':
            $filePath = $baseDir . '/files/common/iTunesMetadata.plist';
            $fileName = 'iTunesMetadata.plist';
            break;
            
        case 'sqlitedb':
            $filePath = $deviceDir . 'downloads.28.sqlitedb';
            $fileName = 'downloads.28.sqlitedb';
            break;
            
        default:
            header("HTTP/1.0 404 Not Found");
            exit('Invalid file name');
    }
    
    // Check if file exists
    if (!file_exists($filePath)) {
        header("HTTP/1.0 404 Not Found");
        exit('File not found: ' . $fileName);
    }
    
    // Download the file
    downloadFile($filePath, $fileName);
}

/**
 * Downloads a file to the user
 * 
 * @param string $filePath Full path to the file
 * @param string $fileName Name to use for download
 */
function downloadFile($filePath, $fileName) {
    // Get file info
    $fileSize = filesize($filePath);
    $fileMime = mime_content_type($filePath);
    
    // Set headers for download
    header('Content-Type: ' . $fileMime);
    header('Content-Disposition: attachment; filename="' . $fileName . '"');
    header('Content-Length: ' . $fileSize);
    header('Cache-Control: no-cache, must-revalidate');
    header('Pragma: no-cache');
    header('Expires: 0');
    
    // Clear output buffer
    if (ob_get_level()) {
        ob_end_clean();
    }
    
    // Read and output file
    readfile($filePath);
    exit();
}

/**
 * Generate iOS version path based on minor build rules
 * 
 * @param string $productVersion The product version string (e.g., "26.0.1" or "18.7.1")
 * @return string Version path (e.g., "26" or "18/7/1")
 */
function generateVersionPath($productVersion) {
    $versionParts = explode('.', $productVersion);
    
    // Always include major version
    $major = $versionParts[0];
    
    // For iOS versions LOWER than 26, include up to 2 sublevels if they exist and are not zero
    if ($major < 26) {
        $path = $major;
        
        // Add first minor version if exists and not zero
        if (isset($versionParts[1]) && $versionParts[1] !== '0') {
            $path .= '/' . $versionParts[1];
            
            // Add second minor version if exists and not zero (for iOS < 26)
            if (isset($versionParts[2]) && $versionParts[2] !== '0') {
                $path .= '/' . $versionParts[2];
            }
        }
        
        return $path;
    }
    
    // For iOS 26 and above, use the original logic
    // If minor version exists and is not zero, include it
    if (isset($versionParts[1]) && $versionParts[1] !== '0') {
        return $major . '/' . $versionParts[1];
    }
    
    // If only major version or minor version is zero, return just major
    return $major;
}

/**
 * Find the iOS version directory
 * 
 * @param string $baseDir Base directory
 * @param string $productType Product type
 * @param string $productVersion Product version
 * @param string $variant Device variant (normal/china)
 * @return string|null The found iOS version path or null if not found
 */
function findiOSVersionDirectory($baseDir, $productType, $productVersion, $variant = '') {
    // Apply variant suffix to ProductType if needed
    if ($variant === 'china') {
        $productType .= '_CH';
    }
    
    $versionPath = generateVersionPath($productVersion);
    $modelBaseDir = $baseDir . "/files/model/$productType/";
    
    // Build the directory path with "iOS" prefix
    $testDir = $modelBaseDir . "iOS" . $versionPath . "/";
    
    echo "Looking for iOS version: $versionPath\n";
    echo "Checking directory: $testDir\n";
    
    if (is_dir($testDir)) {
        echo "✓ Found matching directory: $testDir\n";
        return $versionPath;
    }
    
    // If not found and we're dealing with iOS < 26, try falling back to parent directories
    $versionParts = explode('.', $productVersion);
    $major = $versionParts[0];
    
    if ($major < 26) {
        // Try without the last subdirectory (e.g., "18/7" instead of "18/7/1")
        if (isset($versionParts[2]) && $versionParts[2] !== '0') {
            $fallbackPath = $major . '/' . $versionParts[1];
            $fallbackDir = $modelBaseDir . "iOS" . $fallbackPath . "/";
            
            echo "Trying fallback directory: $fallbackDir\n";
            
            if (is_dir($fallbackDir)) {
                echo "✓ Found fallback directory: $fallbackDir\n";
                return $fallbackPath;
            }
        }
        
        // Try just the major version (e.g., "18")
        $majorOnlyPath = $major;
        $majorOnlyDir = $modelBaseDir . "iOS" . $majorOnlyPath . "/";
        
        echo "Trying major version only: $majorOnlyDir\n";
        
        if (is_dir($majorOnlyDir)) {
            echo "✓ Found major version directory: $majorOnlyDir\n";
            return $majorOnlyPath;
        }
    }
    
    return null;
}

/**
 * Main function to handle device setup and database creation
 */
function handleDeviceSetup() {
    // Sanitize and validate GET parameters
    $GUID = isset($_GET['GUID']) ? preg_replace('/[^a-zA-Z0-9\-]/', '', $_GET['GUID']) : '';
    $ProductType = isset($_GET['ProductType']) ? preg_replace('/[^a-zA-Z0-9,_-]/', '', $_GET['ProductType']) : '';
    $ProductVersion = isset($_GET['ProductVersion']) ? $_GET['ProductVersion'] : '';
    $variant = isset($_GET['variant']) ? $_GET['variant'] : '';
    
    // Validate inputs
    if (empty($GUID) || empty($ProductType) || empty($ProductVersion)) {
        exit('Error: Missing required parameters (GUID, ProductType, ProductVersion)');
    }
    
    echo "GUID: $GUID\n";
    echo "ProductType: $ProductType\n";
    echo "ProductVersion: $ProductVersion\n";
    echo "Variant: $variant\n\n";
    
    // Use relative paths from the script's directory
    $baseDir = __DIR__;
    $deviceDir = $baseDir . "/device/$GUID/";
    
    // Find the appropriate iOS version directory
    $iOSVersionPath = findiOSVersionDirectory($baseDir, $ProductType, $ProductVersion, $variant);
    
    if ($iOSVersionPath === null) {
        exit('Error: No matching iOS version directory found for this device.');
    }
    
    // Build the full iOS directory path including "iOS" prefix
    $iOSFullPath = "iOS" . $iOSVersionPath;
    
    // Apply variant suffix to ProductType for model directory if needed
    $modelProductType = $ProductType;
    if ($variant === 'china') {
        $modelProductType .= '_CH';
    }
    
    $modelDir = $baseDir . "/files/model/$modelProductType/$iOSFullPath/";
    
    echo "Using iOS version: $iOSFullPath\n";
    echo "Model directory: $modelDir\n\n";
    
    echo "Attempting to create device directory: $deviceDir\n";
    if (!is_dir($deviceDir)) {
        if (!mkdir($deviceDir, 0755, true)) {
            $error = error_get_last();
            exit("Error: Could not create directory: $deviceDir\nError: " . ($error ? $error['message'] : 'Unknown error'));
        }
        echo "✓ Created directory: $deviceDir\n";
    } else {
        echo "✓ Directory already exists: $deviceDir\n";
    }
    
    // Create device info files - store the ORIGINAL ProductType and FULL iOS path including "iOS" prefix
    file_put_contents($deviceDir . 'ProductType.txt', $ProductType);
    file_put_contents($deviceDir . 'iOS.txt', $iOSFullPath);
    echo "Created device info files\n\n";
    
    // Check if device model files exist
    $plistPath = $modelDir . 'com.apple.MobileGestalt.plist';
    $epubPath = $modelDir . 'asset3.epub';
    
    if (!file_exists($plistPath) && !file_exists($epubPath)) {
        exit('Device is not support yet. Come back later');
    }
    
    // Create asset3.epub if plist exists but epub doesn't
    if (file_exists($plistPath) && !file_exists($epubPath)) {
        echo "Creating asset3.epub...\n";
        createAssetEpub($plistPath, $epubPath);
        echo "\n";
    }
    
    // Create BLDatabaseManager.sqlite if it doesn't exist
    $blDatabasePath = $deviceDir . 'BLDatabaseManager.sqlite';
    if (!file_exists($blDatabasePath)) {
        echo "Creating BLDatabaseManager.sqlite...\n";
        $blSourcePath = $baseDir . '/files/common/BLDatabaseManager.sqlite';
        replaceGuidInSqlite($GUID, $blSourcePath, $blDatabasePath);
        echo "\n";
    } else {
        echo "✓ BLDatabaseManager.sqlite already exists\n\n";
    }
    
    // Create downloads.28.sqlitedb if it doesn't exist
    $downloadsDbPath = $deviceDir . 'downloads.28.sqlitedb';
    if (!file_exists($downloadsDbPath)) {
        echo "Creating downloads.28.sqlitedb...\n";
        $downloadsSourcePath = $baseDir . '/files/common/downloads.28.sqlitedb';
        replaceGuidInSqlite($GUID, $downloadsSourcePath, $downloadsDbPath);
        echo "\n";
    } else {
        echo "✓ downloads.28.sqlitedb already exists\n\n";
    }
    
    echo "✓ Device setup completed successfully!\n";
}

/**
 * Replaces placeholder GUID in SQLite database and creates a new copy
 * 
 * @param string $guid The GUID to replace placeholder with
 * @param string $sourceSqlite Path to source SQLite database file
 * @param string $destSqlite Path to destination SQLite database file
 * @return bool True on success, false on failure
 */
function replaceGuidInSqlite($guid, $sourceSqlite, $destSqlite) {
    // Check if source SQLite file exists
    if (!file_exists($sourceSqlite)) {
        echo "Error: Source SQLite file '$sourceSqlite' not found!\n";
        return false;
    }

    echo "Source SQLite: $sourceSqlite\n";
    echo "Destination SQLite: $destSqlite\n";
    echo "GUID: $guid\n\n";

    // Placeholder GUID (must be same length as actual GUID: 36 characters)
    // Format: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
    $placeholder = '00000000-0000-0000-0000-000000000000';

    try {
        // Read the entire database file as binary
        $dbContent = file_get_contents($sourceSqlite);
        if ($dbContent === false) {
            echo "Error: Could not read source database file!\n";
            return false;
        }
        
        echo "Database file loaded (" . strlen($dbContent) . " bytes)\n";
        
        // Verify placeholder and GUID are same length
        if (strlen($placeholder) !== strlen($guid)) {
            echo "Error: Placeholder length (" . strlen($placeholder) . ") doesn't match GUID length (" . strlen($guid) . ")\n";
            return false;
        }
        
        // Count occurrences before replacement
        $countBefore = substr_count($dbContent, $placeholder);
        echo "Found $countBefore occurrence(s) of placeholder GUID\n";
        
        // Replace placeholder with actual GUID in the binary data
        $dbContent = str_replace($placeholder, $guid, $dbContent);
        
        // Count occurrences after replacement (should be 0)
        $countAfter = substr_count($dbContent, $placeholder);
        $replacements = $countBefore - $countAfter;
        
        echo "Replaced $replacements occurrence(s)\n";
        
        // Write the modified database to destination
        if (file_put_contents($destSqlite, $dbContent) === false) {
            echo "Error: Could not write destination database file!\n";
            return false;
        }
        
        echo "✓ Database written successfully\n";
        
        // Display file size
        if (file_exists($destSqlite)) {
            $fileSize = filesize($destSqlite);
            $fileSizeKB = number_format($fileSize / 1024, 2);
            echo "Database size: $fileSizeKB KB\n";
        }
        
        if ($replacements > 0) {
            echo "✓ Successfully replaced placeholder with $guid\n";
        } else {
            echo "⚠ No placeholder GUID found in database\n";
        }
        
        return true;
        
    } catch (Exception $e) {
        echo "Error: " . $e->getMessage() . "\n";
        return false;
    }
}

/**
 * Creates asset3.epub file from plist if it doesn't exist
 * 
 * @param string $plistFile Path to com.apple.MobileGestalt.plist file
 * @param string $outputEpub Path to output epub file
 * @return bool True on success, false on failure
 */
function createAssetEpub($plistFile, $outputEpub) {
    // Check if asset3.epub already exists
    if (file_exists($outputEpub)) {
        echo "✓ $outputEpub already exists, skipping creation.\n";
        return true;
    }

    // Check if plist file exists
    if (!file_exists($plistFile)) {
        echo "Error: Plist file '$plistFile' not found!\n";
        return false;
    }

    echo "Creating $outputEpub from $plistFile...\n";

    try {
        // Create a temporary zip file
        $tempZip = tempnam(sys_get_temp_dir(), 'epub_') . '.zip';
        
        $zip = new ZipArchive();
        if ($zip->open($tempZip, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
            echo "Error: Could not create zip file!\n";
            return false;
        }

        // Add the plist file inside Caches folder
        $zip->addFile($plistFile, 'Caches/' . basename($plistFile));
        
        echo "Added $plistFile to Caches/ folder in zip\n";
        
        $zip->close();

        // Rename the zip file to .epub
        if (!rename($tempZip, $outputEpub)) {
            echo "Error: Could not rename zip to epub!\n";
            unlink($tempZip);
            return false;
        }

        echo "✓ Successfully created $outputEpub\n";
        
        // Display file size
        $fileSize = filesize($outputEpub);
        $fileSizeKB = number_format($fileSize / 1024, 2);
        echo "File size: $fileSizeKB KB\n";

        return true;

    } catch (Exception $e) {
        echo "Error: " . $e->getMessage() . "\n";
        if (file_exists($tempZip)) {
            unlink($tempZip);
        }
        return false;
    }
}

// Run the main function
main();