View Raw
# CCLS Games CLI Tool
# Complete Version with Setup, Search, Get functionality, and Logging

# Configuration
$baseUrl = "https://games.ccls.icu"
$cliApiUrl = "$baseUrl/CLI"
$settingsFolder = ".\settings"
$credentialsFile = "$settingsFolder\credentials.dat"
$settingsFile = "$settingsFolder\settings.json" # Using JSON instead of INI for simplicity
$logsFolder = ".\logs" # Logs folder path

# Script-level variables for progress display, logging, and credentials
$script:progressInitialized = $false
$script:topProgressLine = $null
$script:logFile = $null
$script:sessionStartTime = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
# Cache credentials at the script level
$script:cachedCredentials = $null

# Ensure settings and logs directories exist
if (-not (Test-Path $settingsFolder)) {
    New-Item -Path $settingsFolder -ItemType Directory | Out-Null
}

if (-not (Test-Path $logsFolder)) {
    New-Item -Path $logsFolder -ItemType Directory | Out-Null
}

# Initialize log file for the current session
$script:logFile = Join-Path -Path $logsFolder -ChildPath "ccls_session_$($script:sessionStartTime).log"
"CCLS Games CLI Session started at $($script:sessionStartTime)" | Out-File -FilePath $script:logFile

# Custom Write-Host function to handle logging and output filtering
function Write-CCLSHost {
    param (
        [Parameter(Position = 0)]
        [string]$Message = "",
        
        [Parameter()]
        [System.ConsoleColor]$ForegroundColor = [System.ConsoleColor]::White,
        
        [Parameter()]
        [System.ConsoleColor]$BackgroundColor = [System.ConsoleColor]::Black,
        
        [Parameter()]
        [switch]$NoNewline,
        
        [Parameter()]
        [switch]$Log,
        
        [Parameter()]
        [switch]$NoConsole
    )
    
    # Check if the message is marked for removal
    if ($Message.StartsWith('#')) {
        # Don't show in console, but log it if needed
        if ($Log) {
            $cleanMessage = $Message.Substring(1).Trim()
            if (-not [string]::IsNullOrWhiteSpace($cleanMessage)) {
                $cleanMessage | Out-File -FilePath $script:logFile -Append
            }
        }
        return
    }
    
    if ($Message.StartsWith('/')) {
        # Skip completely - don't log or display
        return
    }
    
    # Handle empty lines
    if ([string]::IsNullOrWhiteSpace($Message)) {
        # Display in console if not suppressed
        if (-not $NoConsole) {
            Write-Host "" -NoNewline:$NoNewline
        }
        # But don't log empty lines
        return
    }
    
    # Display in console if not suppressed
    if (-not $NoConsole) {
        Write-Host $Message -ForegroundColor $ForegroundColor -BackgroundColor $BackgroundColor -NoNewline:$NoNewline
    }
    
    # Log if requested
    if ($Log) {
        $plainMessage = $Message
        $plainMessage | Out-File -FilePath $script:logFile -Append
    }
}

# Initialize or load settings
function Initialize-Settings {
    # Get version information using existing function
    $versionInfo = Test-VersionUpdate
    $currentVersion = $versionInfo.CurrentVersion
    
    if (-not (Test-Path $settingsFile)) {
        # Create default settings file
        $defaultSettings = @{
            RememberLogin = $false
            DownloadPath = ".\downloads"
            TempDownloadPath = ".\tmp"
            HasCompletedSetup = $false
            Version = $currentVersion  # Add version to settings
        }
        $defaultSettings | ConvertTo-Json | Set-Content -Path $settingsFile
        
        # Return settings without version change flag
        return $defaultSettings
    }
    
    # Load settings
    $settings = Get-Content -Path $settingsFile | ConvertFrom-Json
    
    # Check if Version property exists, add it if not
    if (-not (Get-Member -InputObject $settings -Name "Version" -MemberType Properties)) {
        $settings | Add-Member -MemberType NoteProperty -Name "Version" -Value $currentVersion
        $settings | ConvertTo-Json | Set-Content -Path $settingsFile
    }
    
    # Check if version has changed and update if needed
    if ($settings.Version -ne $currentVersion) {
        Write-CCLSHost "#Detected version change from $($settings.Version) to $currentVersion" -Log -NoConsole
        # Store the old version
        $oldVersion = $settings.Version
        
        # Update to new version
        $settings.Version = $currentVersion
        $settings | ConvertTo-Json | Set-Content -Path $settingsFile
        
        # Keep track that version has changed for later notification
        $script:versionChanged = $true
        $script:previousVersion = $oldVersion
    }
    
    return $settings
}

# Save settings
function Save-Settings($settings) {
    $settings | ConvertTo-Json | Set-Content -Path $settingsFile
}

# Store credentials securely
function Save-Credentials($username, $password) {
    $credentials = @{
        Username = $username
        Password = $password
    } | ConvertTo-Json
    
    # Simple encryption (replace with more secure method if needed)
    $securePassword = ConvertTo-SecureString -String $credentials -AsPlainText -Force
    $encryptedText = ConvertFrom-SecureString -SecureString $securePassword
    
    # Save to file
    $encryptedText | Set-Content -Path $credentialsFile
}

# Load stored credentials
function Get-StoredCredentials {
    if (Test-Path $credentialsFile) {
        try {
            $encryptedText = Get-Content -Path $credentialsFile
            $securePassword = ConvertTo-SecureString -String $encryptedText
            $credentials = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
                [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($securePassword)
            )
            return $credentials | ConvertFrom-Json
        }
        catch {
            Write-CCLSHost "Error reading credentials: $($_.Exception.Message)" -ForegroundColor Red -Log
            return $null
        }
    }
    return $null
}

# Run setup process
function Start-Setup {
    Write-CCLSHost "`n`nCCLS Games CLI Setup" -ForegroundColor Green -Log
    Write-CCLSHost "=====================" -ForegroundColor Green -Log
    Write-CCLSHost "Please configure the following settings:`n" -ForegroundColor Cyan -Log
    
    $settings = Initialize-Settings
    
    # Get game installation directory
    $validPath = $false
    while (-not $validPath) {
        Write-CCLSHost "Set your games default installation directory: " -ForegroundColor Yellow -NoNewline -Log
        $downloadPath = Read-Host
        Write-CCLSHost "$downloadPath" -NoConsole -Log
        
        if ([string]::IsNullOrWhiteSpace($downloadPath)) {
            Write-CCLSHost "Please enter a valid directory path." -ForegroundColor Red -Log
        }
        else {
            # Create directory if it doesn't exist
            if (-not (Test-Path $downloadPath)) {
                try {
                    New-Item -ItemType Directory -Path $downloadPath -Force | Out-Null
                    $validPath = $true
                }
                catch {
                    Write-CCLSHost "Error creating directory: $($_.Exception.Message)" -ForegroundColor Red -Log
                }
            }
            else {
                $validPath = $true
            }
        }
    }
    
    # Get temporary download directory
    $validTempPath = $false
    while (-not $validTempPath) {
        Write-CCLSHost "Set the temporary directory of downloading files before they have finished downloading: " -ForegroundColor Yellow -NoNewline -Log
        $tempDownloadPath = Read-Host
        Write-CCLSHost "$tempDownloadPath" -NoConsole -Log
        
        if ([string]::IsNullOrWhiteSpace($tempDownloadPath)) {
            Write-CCLSHost "Please enter a valid directory path." -ForegroundColor Red -Log
        }
        else {
            # Create directory if it doesn't exist
            if (-not (Test-Path $tempDownloadPath)) {
                try {
                    New-Item -ItemType Directory -Path $tempDownloadPath -Force | Out-Null
                    $validTempPath = $true
                }
                catch {
                    Write-CCLSHost "Error creating directory: $($_.Exception.Message)" -ForegroundColor Red -Log
                }
            }
            else {
                $validTempPath = $true
            }
        }
    }
    
    # Update settings
    $settings.DownloadPath = $downloadPath
    $settings.TempDownloadPath = $tempDownloadPath
    $settings.HasCompletedSetup = $true
    Save-Settings -settings $settings
    
    Write-CCLSHost "`nGreat, you have now completed the setup. Type 'help' for a list of commands to get you started." -ForegroundColor Green -Log
}

# Validate username against server
function Test-Username($username) {
    $params = @{
        Uri = "$cliApiUrl/username_check.php"
        Method = "POST"
        Headers = @{
            "User-Agent" = "CCLS-CLI/1.0"
        }
        Body = @{
            username = $username
        }
    }
    
    try {
        $response = Invoke-RestMethod @params
        return $response.exists
    }
    catch {
        Write-CCLSHost "Error connecting to the server: $($_.Exception.Message)" -ForegroundColor Red -Log
        return $false
    }
}

# Validate password against server
function Test-Password($username, $password) {
    $params = @{
        Uri = "$cliApiUrl/password_check.php"
        Method = "POST"
        Headers = @{
            "User-Agent" = "CCLS-CLI/1.0"
        }
        Body = @{
            username = $username
            password = $password
        }
    }
    
    try {
        $response = Invoke-RestMethod @params
        return $response.success
    }
    catch {
        Write-CCLSHost "Error connecting to the server: $($_.Exception.Message)" -ForegroundColor Red -Log
        return $false
    }
}

function Start-AutoLogin {
    $credentials = Get-StoredCredentials
    if ($credentials -ne $null) {
        Write-CCLSHost "#Attempting to login with stored credentials..." -Log
        
        if (Test-Password -username $credentials.Username -password $credentials.Password) {
            Write-CCLSHost "#Auto-login successful!" -Log
            
            # Cache the credentials for the session
            $script:cachedCredentials = @{
                Username = $credentials.Username
                Password = $credentials.Password
            }
            
            return @{
                Success = $true
                Username = $credentials.Username
            }
        }
        else {
            Write-CCLSHost "Stored credentials are no longer valid." -ForegroundColor Yellow -Log
            # Remove invalid credentials
            if (Test-Path $credentialsFile) {
                Remove-Item -Path $credentialsFile -Force
            }
        }
    }
    
    return @{
        Success = $false
    }
}

function Start-ManualLogin {
    $maxAttempts = 3
    $attempts = 0
    
    while ($attempts -lt $maxAttempts) {
        Write-CCLSHost "Username: " -ForegroundColor Cyan -NoNewline -Log
        $username = Read-Host
        Write-CCLSHost "$username" -NoConsole -Log
        
        # Check if username exists
        Write-CCLSHost "#Checking username..." -Log
        if (Test-Username -username $username) {
            Write-CCLSHost "#Username found!" -Log
            
            Write-CCLSHost "Password: " -ForegroundColor Cyan -NoNewline -Log
            $password = Read-Host -AsSecureString
            $passwordPlain = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
                [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)
            )
            Write-CCLSHost "********" -NoConsole -Log
            
            Write-CCLSHost "#Validating password..." -Log
            if (Test-Password -username $username -password $passwordPlain) {
                Write-CCLSHost "#Login successful!" -Log
                
                # Cache the credentials for the session
                $script:cachedCredentials = @{
                    Username = $username
                    Password = $passwordPlain
                }
                
                # Ask if user wants to save credentials - no newline before this
                Write-CCLSHost "Do you want to remember your login info for next time? (Y/N)" -ForegroundColor Yellow -Log
                $rememberLogin = Read-Host
                Write-CCLSHost "$rememberLogin" -NoConsole -Log
                
                if ($rememberLogin.ToLower() -eq "y") {
                    Save-Credentials -username $username -password $passwordPlain
                    $settings = Initialize-Settings
                    $settings.RememberLogin = $true
                    Save-Settings -settings $settings
                    Write-CCLSHost "#Login information saved." -Log
                }
                
                return @{
                    Success = $true
                    Username = $username
                }
            }
            else {
                Write-CCLSHost "Incorrect password, please try again." -ForegroundColor Red -Log
                $attempts++
            }
        }
        else {
            Write-CCLSHost "Username not found, please try again." -ForegroundColor Red -Log
            $attempts++
        }
    }
    
    Write-CCLSHost "Too many failed login attempts. Please try again later." -ForegroundColor Red -Log
    return @{
        Success = $false
    }
}

# Updated Install-Utility function
function Install-Utility {
    param (
        [string]$UtilityName
    )
    
    # Handle different utilities
    switch ($UtilityName.ToLower()) {
        "7zip" {
            Install7Zip
        }
        "requests" {
            InstallPythonRequests
        }
        "python" {
            Install-Python
        }
        default {
            Write-CCLSHost "Unsupported utility: $UtilityName" -ForegroundColor Red -Log
            Write-CCLSHost "Currently supported utilities: 7zip, requests, python" -ForegroundColor Green -Log
        }
    }
}

# Function to install 7-Zip (internal function for Install-Utility)
function Install7Zip {
    # Determine the current script directory
    $scriptLocation = if ($PSScriptRoot) {
        # If running from a script, use its location
        $PSScriptRoot
    } else {
        # If running in console, use current directory
        (Get-Location).Path
    }
    
    # Target directory is the script location
    $targetDir = $scriptLocation
    
    # URLs for download
    $zipUrl = "https://games.ccls.icu/CLI/downloads/7zip.zip"
    $zipPath = Join-Path -Path $targetDir -ChildPath "7zip.zip"
    
    Write-CCLSHost "Starting 7-Zip installation..." -ForegroundColor Cyan -Log
    
    try {
        # Download the zip file
        Write-CCLSHost "Downloading 7-Zip package from $zipUrl" -ForegroundColor Yellow -Log
        
        $webClient = New-Object System.Net.WebClient
        $webClient.Headers.Add("User-Agent", "CCLS-CLI/1.0")
        $webClient.DownloadFile($zipUrl, $zipPath)
        
        if (-not (Test-Path $zipPath)) {
            Write-CCLSHost "Failed to download 7-Zip package." -ForegroundColor Red -Log
            return
        }
        
        Write-CCLSHost "Download completed successfully." -ForegroundColor Green -Log
        
        # Create temporary extraction directory
        $tempExtractPath = Join-Path -Path $targetDir -ChildPath "7zip_temp"
        if (Test-Path $tempExtractPath) {
            Remove-Item -Path $tempExtractPath -Recurse -Force
        }
        New-Item -ItemType Directory -Path $tempExtractPath -Force | Out-Null
        
        # Final 7zip directory
        $finalPath = Join-Path -Path $targetDir -ChildPath "7zip"
        if (Test-Path $finalPath) {
            Remove-Item -Path $finalPath -Recurse -Force
        }
        
        # Extract the zip file to temp location
        Write-CCLSHost "Extracting 7-Zip package..." -ForegroundColor Yellow -Log
        
        $extractionSuccess = $false
        
        try {
            # Try to use built-in Expand-Archive
            Expand-Archive -Path $zipPath -DestinationPath $tempExtractPath -Force
            $extractionSuccess = $true
        }
        catch {
            Write-CCLSHost "#Built-in extraction failed, trying alternate method: $($_.Exception.Message)" -ForegroundColor Yellow -Log -NoConsole
            
            try {
                # Alternative extraction method using .NET
                Add-Type -AssemblyName System.IO.Compression.FileSystem
                [System.IO.Compression.ZipFile]::ExtractToDirectory($zipPath, $tempExtractPath)
                $extractionSuccess = $true
            }
            catch {
                Write-CCLSHost "Extraction failed: $($_.Exception.Message)" -ForegroundColor Red -Log
                $extractionSuccess = $false
            }
        }
        
        # Fix nested folder issue if extraction was successful
        if ($extractionSuccess) {
            # Check if we have a nested 7zip folder
            $nestedFolder = Join-Path -Path $tempExtractPath -ChildPath "7zip"
            if (Test-Path $nestedFolder) {
                # Move the contents from nested folder to final location
                Write-CCLSHost "#Fixing folder structure..." -Log -NoConsole
                Move-Item -Path $nestedFolder -Destination $targetDir -Force
                $extractionSuccess = $true
            } else {
                # If no nested folder, just rename temp folder to final name
                Rename-Item -Path $tempExtractPath -NewName "7zip"
                $extractionSuccess = $true
            }
        }
        
        # Clean up the downloaded zip file
        if (Test-Path $zipPath) {
            Remove-Item -Path $zipPath -Force
            Write-CCLSHost "#Removed temporary download file." -ForegroundColor Gray -Log -NoConsole
        }
        
        # Clean up temp folder if it still exists
        if (Test-Path $tempExtractPath) {
            Remove-Item -Path $tempExtractPath -Recurse -Force
            Write-CCLSHost "#Removed temporary extraction folder." -ForegroundColor Gray -Log -NoConsole
        }
        
        # Verify installation
        $exePath = Join-Path -Path $finalPath -ChildPath "7z.exe"
        if ($extractionSuccess -and (Test-Path $exePath)) {
            Write-CCLSHost "7-Zip has been successfully installed to $finalPath" -ForegroundColor Green -Log
            Write-CCLSHost "You can now use 7-Zip for file extraction." -ForegroundColor Green -Log
        }
        else {
            Write-CCLSHost "7-Zip installation was not completed successfully." -ForegroundColor Red -Log
            Write-CCLSHost "Please try again or manually install 7-Zip." -ForegroundColor Yellow -Log
        }
    }
    catch {
        Write-CCLSHost "Error during installation: $($_.Exception.Message)" -ForegroundColor Red -Log
        Write-CCLSHost "7-Zip installation failed." -ForegroundColor Red -Log
    }
}

# Function to install Python requests library (internal function for Install-Utility)
function InstallPythonRequests {
    Write-CCLSHost "Checking for Python installation..." -ForegroundColor Cyan -Log
    
    # First check if Python is installed
    try {
        $pythonResult = python --version 2>&1
        if ($pythonResult -match "Python (\d+\.\d+\.\d+)") {
            $pythonVersion = $matches[1]
            Write-CCLSHost "Python detected (v$pythonVersion)" -ForegroundColor Green -Log
        } else {
            Write-CCLSHost "Python not detected" -ForegroundColor Red -Log
            Write-CCLSHost "Please install Python first before installing the requests library." -ForegroundColor Yellow -Log
            Write-CCLSHost "Download Python from: https://www.python.org/downloads/" -ForegroundColor Yellow -Log
            return
        }
    } catch {
        Write-CCLSHost "Python is not installed or not in the system PATH." -ForegroundColor Red -Log
        Write-CCLSHost "Please install Python first before installing the requests library." -ForegroundColor Yellow -Log
        Write-CCLSHost "Download Python from: https://www.python.org/downloads/" -ForegroundColor Yellow -Log
        return
    }
    
    # Check if requests is already installed
    Write-CCLSHost "Checking if requests library is already installed..." -ForegroundColor Cyan -Log
    
    try {
        $requestsCheck = python -c "import requests; print('Installed (v{0})'.format(requests.__version__))" 2>&1
        if ($requestsCheck -match "Installed \(v([\d\.]+)\)") {
            $requestsVersion = $matches[1]
            Write-CCLSHost "The requests library is already installed (v$requestsVersion)" -ForegroundColor Green -Log
            
            # Ask if user wants to upgrade
            Write-CCLSHost "Do you want to upgrade to the latest version? (Y/N)" -ForegroundColor Yellow -Log
            $upgradeConfirmation = Read-Host
            Write-CCLSHost "$upgradeConfirmation" -NoConsole -Log
            
            if ($upgradeConfirmation.ToLower() -ne "y") {
                Write-CCLSHost "Installation skipped." -ForegroundColor Yellow -Log
                return
            }
            
            # If yes, set upgrade flag
            $upgradeFlag = "--upgrade"
        } else {
            # Not installed
            $upgradeFlag = ""
        }
    } catch {
        # Not installed or error checking
        Write-CCLSHost "The requests library is not installed." -ForegroundColor Yellow -Log
        $upgradeFlag = ""
    }
    
    Write-CCLSHost "Installing Python requests library..." -ForegroundColor Cyan -Log
    
    try {
        # Use Start-Process with -Wait to run pip in the background
        $pipCommand = "pip"
        $pipArgs = "install $upgradeFlag requests"
        
        # Temporary files for output and error
        $tempOutputFile = [System.IO.Path]::GetTempFileName()
        $tempErrorFile = [System.IO.Path]::GetTempFileName()
        
        Write-CCLSHost "#Running: $pipCommand $pipArgs" -Log -NoConsole
        
        # Show progress indicator
        Write-CCLSHost "Installing..." -NoNewline -ForegroundColor Yellow -Log
        
        # Run pip in background and redirect output to temp files
        $process = Start-Process -FilePath $pipCommand -ArgumentList $pipArgs -NoNewWindow -PassThru -RedirectStandardOutput $tempOutputFile -RedirectStandardError $tempErrorFile -Wait
        
        # Read output and error from temp files
        $output = Get-Content -Path $tempOutputFile -Raw
        $error = Get-Content -Path $tempErrorFile -Raw
        
        # Clean up temp files
        Remove-Item -Path $tempOutputFile -Force -ErrorAction SilentlyContinue
        Remove-Item -Path $tempErrorFile -Force -ErrorAction SilentlyContinue
        
        Write-CCLSHost "" -Log  # Newline after progress indicator
        
        # Verify installation regardless of process exit code
        # This is more reliable than checking process exit code
        $installSuccess = $false
        try {
            $verifyResult = python -c "import requests; print('Installed (v{0})'.format(requests.__version__))" 2>&1
            if ($verifyResult -match "Installed \(v([\d\.]+)\)") {
                $installSuccess = $true
                $newVersion = $matches[1]
            }
        } catch {
            $installSuccess = $false
        }
        
        if ($installSuccess) {
            # Check if output contains "Successfully installed" as additional confirmation
            if (-not [string]::IsNullOrWhiteSpace($output) -and 
                ($output -match "Successfully installed" -or $output -match "Requirement already satisfied")) {
                Write-CCLSHost "Python requests library v$newVersion installed successfully!" -ForegroundColor Green -Log
                
                # Show summary of what happened
                if ($output -match "Requirement already satisfied") {
                    Write-CCLSHost "All requirements were already satisfied." -ForegroundColor Green -Log
                } else {
                    Write-CCLSHost "Installation completed successfully." -ForegroundColor Green -Log
                }
            } else {
                Write-CCLSHost "Python requests library appears to be installed (v$newVersion)" -ForegroundColor Green -Log
                Write-CCLSHost "But the installation process reported unusual output." -ForegroundColor Yellow -Log
            }
        } else {
            Write-CCLSHost "Failed to install Python requests library." -ForegroundColor Red -Log
            if (-not [string]::IsNullOrWhiteSpace($error)) {
                Write-CCLSHost "Error details:" -ForegroundColor Red -Log
                Write-CCLSHost $error -ForegroundColor Red -Log
            }
            if (-not [string]::IsNullOrWhiteSpace($output)) {
                Write-CCLSHost "Output details:" -ForegroundColor Yellow -Log
                Write-CCLSHost $output -ForegroundColor Yellow -Log
            }
        }
    } catch {
        Write-CCLSHost "Error during installation: $($_.Exception.Message)" -ForegroundColor Red -Log
    }
}

# Function to install Python
function Install-Python {
    Write-CCLSHost "Starting Python installation process..." -ForegroundColor Cyan -Log
    
    # Create a temporary directory for the download
    $tempDir = [System.IO.Path]::GetTempPath()
    $tempDownloadPath = Join-Path -Path $tempDir -ChildPath "python_installer.exe"
    
    # Determine if system is 64-bit or 32-bit
    $is64Bit = [Environment]::Is64BitOperatingSystem
    
    # Get Python version info from our server
    try {
        Write-CCLSHost "Retrieving Python version information..." -ForegroundColor Yellow -Log
        $webClient = New-Object System.Net.WebClient
        $webClient.Headers.Add("User-Agent", "CCLS-CLI/1.0")
        
        # Use the CCLS API endpoint to get Python version info
        $pythonInfoJson = $webClient.DownloadString("$cliApiUrl/install_python.php")
        $pythonInfo = $pythonInfoJson | ConvertFrom-Json
        
        # Use the appropriate URL based on system architecture
        if ($is64Bit) {
            $pythonUrl = $pythonInfo.windows_64bit_url
            Write-CCLSHost "Using 64-bit installer for Python $($pythonInfo.version)" -ForegroundColor Green -Log
        } else {
            $pythonUrl = $pythonInfo.windows_32bit_url
            Write-CCLSHost "Using 32-bit installer for Python $($pythonInfo.version)" -ForegroundColor Green -Log
        }
    } catch {
        Write-CCLSHost "Error retrieving Python information from server: $($_.Exception.Message)" -ForegroundColor Red -Log
        Write-CCLSHost "Installation cannot proceed. Please try again later." -ForegroundColor Red -Log
        return
    }
    
    # Download the Python installer
    try {
        Write-CCLSHost "Starting download from $pythonUrl" -ForegroundColor Yellow -Log
        $webClient = New-Object System.Net.WebClient
        $webClient.Headers.Add("User-Agent", "CCLS-CLI/1.0")
        
        Write-CCLSHost "Downloading Python installer to $tempDownloadPath..." -ForegroundColor Cyan -Log
        Write-CCLSHost "Download in progress, this may take a few minutes depending on your connection speed..." -ForegroundColor Yellow -Log
        
        # Use synchronous download with simple progress indication
        $sw = [System.Diagnostics.Stopwatch]::StartNew()
        $webClient.DownloadFile($pythonUrl, $tempDownloadPath)
        $sw.Stop()
        
        if (Test-Path $tempDownloadPath) {
            $fileSize = (Get-Item $tempDownloadPath).Length / 1MB
            Write-CCLSHost "Download completed successfully! Downloaded $([Math]::Round($fileSize, 2)) MB in $([Math]::Round($sw.Elapsed.TotalSeconds, 1)) seconds." -ForegroundColor Green -Log
        } else {
            Write-CCLSHost "Download failed - file not found at expected location." -ForegroundColor Red -Log
            return
        }
    } catch {
        Write-CCLSHost "Error downloading Python installer: $($_.Exception.Message)" -ForegroundColor Red -Log
        return
    }
    
    # Launch the installer
    try {
        Write-CCLSHost "Starting Python installer..." -ForegroundColor Green -Log
        Write-CCLSHost "Please follow the on-screen instructions to complete the installation." -ForegroundColor Yellow -Log
        Write-CCLSHost "Recommended options:" -ForegroundColor Yellow -Log
        Write-CCLSHost " - Check 'Add Python to PATH'" -ForegroundColor Yellow -Log
        Write-CCLSHost " - Choose 'Customize installation' for more options" -ForegroundColor Yellow -Log
        Write-CCLSHost " - Ensure 'pip' is selected in the optional features" -ForegroundColor Yellow -Log
        
        # Start the installer
        $process = Start-Process -FilePath $tempDownloadPath -Wait -PassThru
        
        # Handle different exit codes
        if ($process.ExitCode -eq 0) {
            Write-CCLSHost "Python installation process completed successfully." -ForegroundColor Green -Log
        } elseif ($process.ExitCode -eq 1602) {
            Write-CCLSHost "Installation was cancelled by the user." -ForegroundColor Yellow -Log
        } else {
            Write-CCLSHost "Python installer exited with code: $($process.ExitCode)" -ForegroundColor Yellow -Log
        }
        
        Write-CCLSHost "To verify the installation, type 'python --version' in a new command prompt window." -ForegroundColor Cyan -Log
    } catch {
        Write-CCLSHost "Error launching Python installer: $($_.Exception.Message)" -ForegroundColor Red -Log
    }
    
    # Clean up the downloaded file
    try {
        if (Test-Path $tempDownloadPath) {
            Remove-Item -Path $tempDownloadPath -Force
            Write-CCLSHost "Cleaned up temporary installer file." -ForegroundColor Gray -Log -NoConsole
        }
    } catch {
        Write-CCLSHost "Note: Could not remove temporary installer file: $($_.Exception.Message)" -ForegroundColor Yellow -Log -NoConsole
    }
}

function Search-Game($id) {
    # Validate ID format - now supports both cg0000 and cb0000 formats
    if ($id -notmatch "^(cg|cb)\d{4}$") {
        Write-CCLSHost "Invalid ID format. Please use format 'cg0000' for games or 'cb0000' for bundles." -ForegroundColor Red -Log
        return
    }
    
    # Check if credentials are cached
    if ($null -eq $script:cachedCredentials) {
        Write-CCLSHost "Error: Not logged in. Please restart the application and log in." -ForegroundColor Red -Log
        return
    }
    
    # Determine if this is a game or bundle
    $isBundle = $id -match "^cb\d{4}$"
    $itemType = if ($isBundle) { "bundle" } else { "game" }
    
    try {
        # Set up request parameters with credentials
        $params = @{
            Uri = "$cliApiUrl/search.php"
            Method = "POST"
            Headers = @{
                "User-Agent" = "CCLS-CLI/1.0"
            }
            Body = @{
                username = $script:cachedCredentials.Username
                password = $script:cachedCredentials.Password
                id = $id
            }
        }
        
        Write-CCLSHost "#Searching for $itemType information..." -Log
        
        # Fetch data from server
        try {
            $response = Invoke-RestMethod @params
            
            # Check if the request was successful
            if (-not $response.success) {
                Write-CCLSHost "Error: $($response.message)" -ForegroundColor Red -Log
                return
            }
            
            $itemInfo = $response
        }
        catch {
            Write-CCLSHost "Error fetching $itemType information: $($_.Exception.Message)" -ForegroundColor Red -Log
            return
        }
        
        # Display item information in a formatted way
        Write-CCLSHost "`n==========================================================" -ForegroundColor DarkGray -Log
        Write-CCLSHost "$($itemType.ToUpper()) Information for $($itemInfo.name) ($($itemInfo.id))" -ForegroundColor Green -Log
        Write-CCLSHost "==========================================================" -ForegroundColor DarkGray -Log
        
        Write-CCLSHost "`nDescription:" -ForegroundColor Cyan -Log
        Write-CCLSHost $itemInfo.description -Log
        
        if ($itemInfo.safety_score -or $itemInfo.safety_level) {
            Write-CCLSHost "`nSafety:" -ForegroundColor Cyan -Log
            if ($itemInfo.safety_score) { Write-CCLSHost "Score: $($itemInfo.safety_score)" -Log }
            if ($itemInfo.safety_level) { Write-CCLSHost "Level: $($itemInfo.safety_level)" -Log }
        }
        
        Write-CCLSHost "`nDetails:" -ForegroundColor Cyan -Log
        
        # Handle different size properties for game vs bundle
        if ($isBundle) {
            if ($itemInfo.zipped_size) { Write-CCLSHost "Zipped Size: $($itemInfo.zipped_size)" -Log }
            if ($itemInfo.unzipped_size) { Write-CCLSHost "Unzipped Size: $($itemInfo.unzipped_size)" -Log }
            if ($itemInfo.games_included) { Write-CCLSHost "Games Included: $($itemInfo.games_included)" -Log }
        } else {
            if ($itemInfo.size) { Write-CCLSHost "Size: $($itemInfo.size)" -Log }
        }
        
        if ($itemInfo.version -and $itemInfo.version -ne "") { Write-CCLSHost "Version: $($itemInfo.version)" -Log }
        
        if (($itemInfo.online -and $itemInfo.online -ne "") -or 
            ($itemInfo.steam -and $itemInfo.steam -ne "") -or 
            ($itemInfo.epic -and $itemInfo.epic -ne "")) {
            Write-CCLSHost "`nAvailability:" -ForegroundColor Cyan -Log
            if ($itemInfo.online -and $itemInfo.online -ne "") { Write-CCLSHost "Online: $($itemInfo.online)" -Log }
            if ($itemInfo.steam -and $itemInfo.steam -ne "") { Write-CCLSHost "Steam: $($itemInfo.steam)" -Log }
            if ($itemInfo.epic -and $itemInfo.epic -ne "") { Write-CCLSHost "Epic: $($itemInfo.epic)" -Log }
        }
        
        if ($itemInfo.false_av -and $itemInfo.false_av -ne "") {
            Write-CCLSHost "`nNote: " -ForegroundColor Yellow -NoNewline -Log
            Write-CCLSHost "This $itemType may trigger false antivirus alerts: $($itemInfo.false_av)" -Log
        }
        
        # If it's a game, show system requirements
        if (-not $isBundle -and $itemInfo.system_requirements) {
            Write-CCLSHost "`nSystem Requirements:" -ForegroundColor Cyan -Log
            
            if ($itemInfo.system_requirements.minimum) {
                Write-CCLSHost "Minimum:" -ForegroundColor Yellow -Log
                foreach ($prop in $itemInfo.system_requirements.minimum.PSObject.Properties) {
                    Write-CCLSHost "  $($prop.Name): $($prop.Value)" -Log
                }
            }
            
            if ($itemInfo.system_requirements.recommended) {
                Write-CCLSHost "`nRecommended:" -ForegroundColor Yellow -Log
                foreach ($prop in $itemInfo.system_requirements.recommended.PSObject.Properties) {
                    Write-CCLSHost "  $($prop.Name): $($prop.Value)" -Log
                }
            }
        }
        
        Write-CCLSHost "#Press any key to return to the main menu..." -Log
        $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    }
    catch {
        Write-CCLSHost "An error occurred while processing $itemType information: $($_.Exception.Message)" -ForegroundColor Red -Log
        Write-CCLSHost "#Press any key to return to the main menu..." -Log
        $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    }
}

# Function to format file size
function Format-FileSize {
    param ([string]$Size)
    
    if ([string]::IsNullOrEmpty($Size)) {
        return "Unknown Size"
    }
    
    # Extract numeric part and unit
    if ($Size -match "(\d+\.?\d*)\s*(GB|MB|KB|B)") {
        $value = [double]$matches[1]
        $unit = $matches[2]
        
        return "$value $unit"
    }
    
    return $Size
}

function Get-Game {
    param (
        [string]$id,
        [switch]$SkipConfirmation
    )
    
    # Validate ID format - now supports both cg0000 and cb0000 formats
    if ($id -notmatch "^(cg|cb)\d{4}$") {
        Write-CCLSHost "Invalid ID format. Please use format 'cg0000' for games or 'cb0000' for bundles." -ForegroundColor Red -Log
        return
    }
    
    # Check if credentials are cached
    if ($script:cachedCredentials -ne $null -and ($null -eq $script:cachedCredentials.Username -or $null -eq $script:cachedCredentials.Password)) {
        Write-CCLSHost "Error: Not logged in. Please restart the application and log in." -ForegroundColor Red -Log
        return
    }
    
    # Determine if this is a game or bundle
    $isBundle = $id -match "^cb\d{4}$"
    $itemType = if ($isBundle) { "bundle" } else { "game" }
    
    # Check if setup has been completed
    $settings = Initialize-Settings
    if (-not $settings.HasCompletedSetup) {
        Write-CCLSHost "ALERT, you must run the 'setup' command before downloading." -ForegroundColor Red -Log
        return
    }
    
    # Ensure download directories exist
    if (-not (Test-Path $settings.DownloadPath)) {
        try {
            New-Item -ItemType Directory -Path $settings.DownloadPath -Force | Out-Null
        }
        catch {
            Write-CCLSHost "Error creating download directory: $($_.Exception.Message)" -ForegroundColor Red -Log
            return
        }
    }
    
    if (-not (Test-Path $settings.TempDownloadPath)) {
        try {
            New-Item -ItemType Directory -Path $settings.TempDownloadPath -Force | Out-Null
        }
        catch {
            Write-CCLSHost "Error creating temporary download directory: $($_.Exception.Message)" -ForegroundColor Red -Log
            return
        }
    }
    
    # Get game info and download information
    try {
        # First, fetch the detailed information about the game
        $infoParams = @{
            Uri = "$cliApiUrl/search.php"
            Method = "POST"
            Headers = @{
                "User-Agent" = "CCLS-CLI/1.0"
            }
            Body = @{
                username = $script:cachedCredentials.Username
                password = $script:cachedCredentials.Password
                id = $id
            }
        }
        
        Write-CCLSHost "#Fetching $itemType information..." -Log -NoConsole
        
        try {
            $itemInfo = Invoke-RestMethod @infoParams
            
            if (-not $itemInfo.success) {
                Write-CCLSHost "Error fetching $itemType information: $($itemInfo.message)" -ForegroundColor Red -Log
                return
            }
            
            Write-CCLSHost "#Successfully fetched $itemType information for later use" -Log -NoConsole
        }
        catch {
            Write-CCLSHost "Error fetching $itemType information: $($_.Exception.Message)" -ForegroundColor Red -Log
            return
        }
        
        # Now fetch download information
        $params = @{
            Uri = "$cliApiUrl/get.php"
            Method = "POST"
            Headers = @{
                "User-Agent" = "CCLS-CLI/1.0"
            }
            Body = @{
                username = $script:cachedCredentials.Username
                password = $script:cachedCredentials.Password
                id = $id
            }
        }
        
        Write-CCLSHost "#Fetching $itemType download information..." -Log -NoConsole
        
        $response = Invoke-RestMethod @params
        
        if (-not $response.success) {
            Write-CCLSHost "Error: $($response.message)" -ForegroundColor Red -Log
            return
        }
        
        $itemName = $response.name
        $itemId = $response.id
        $downloadUrl = $response.download_url
        $itemSize = $response.size
        
        # Create download file name from URL
        $fileName = Split-Path -Path $downloadUrl -Leaf
        if ([string]::IsNullOrEmpty($fileName)) {
            $fileName = "$itemId.7z"
        }
        
        $downloadPath = Join-Path -Path $settings.TempDownloadPath -ChildPath $fileName
        
        # Confirm download with user
        Write-CCLSHost "==========================================================" -ForegroundColor DarkGray -Log
        Write-CCLSHost "$($itemType.ToUpper()) Download: $itemName ($itemId)" -ForegroundColor Green -Log
        Write-CCLSHost "==========================================================" -ForegroundColor DarkGray -Log
        Write-CCLSHost "Size: $itemSize" -ForegroundColor Yellow -Log
        
        $proceed = $true
        if (-not $SkipConfirmation) {
            Write-CCLSHost "Do you want to proceed with the download? (Y/N)" -ForegroundColor Yellow -Log
            
            $confirmation = Read-Host
            Write-CCLSHost "$confirmation" -NoConsole -Log
            
            if ($confirmation.ToLower() -ne "y") {
                Write-CCLSHost "Download cancelled by user." -ForegroundColor Yellow -Log
                return
            }
        }
        else {
            Write-CCLSHost "#Automatically proceeding with download (confirmation skipped)..." -ForegroundColor Green -Log -NoConsole
        }
        
        # Flag to track if download was successfully completed
        $downloadSuccessful = $false
        
        try {
            # Try to invoke Python to check if it's available
            $pythonVersion = python --version 2>&1
            $pythonAvailable = $true
            Write-CCLSHost "#Python detected: $pythonVersion" -Log -NoConsole
            
            # Determine the actual location of the Python script
            $scriptLocation = if ($PSScriptRoot) {
                # If running from a script, use its location
                $PSScriptRoot
            } else {
                # If running in console, use current directory
                (Get-Location).Path
            }

            $pythonScript = Join-Path -Path $scriptLocation -ChildPath "ccls_downloader.py"

            # Debug the script path
            Write-CCLSHost "#Python script path: $pythonScript" -Log -NoConsole

            # Always recreate the Python script on each run
            if (Test-Path $pythonScript) {
                Remove-Item -Path $pythonScript -Force
                Write-CCLSHost "#Removed existing Python script" -Log -NoConsole
            }
            
            # Create a new copy of the script with the latest code
            Write-CCLSHost "#Creating Python script at $pythonScript" -Log -NoConsole
            
            # Python downloader script content
            $pythonCode = @'
#!/usr/bin/env python3
"""
CCLS High-Speed Downloader (Silent Version with Ctrl+Z stop)
--------------------------------------------
A high-performance Python script for downloading games from CCLS with improved
connection handling, retry logic, resume capabilities, and URL encoding fixes,
with minimal output to keep the console clean. Uses Ctrl+Z to stop downloads.
"""

import os
import sys
import time
import requests
import signal
import random
import msvcrt  # For Windows key detection
import urllib.parse
from datetime import datetime, timedelta
from threading import Thread, Event

# Constants for downloading
CHUNK_SIZE = 1024 * 1024  # 1MB chunks for better performance
USER_AGENT = "CCLS-CLI/1.0 (Python Downloader)"
MAX_RETRIES = 5  # Increased from 3
CONNECT_TIMEOUT = 30  # Connection timeout in seconds
READ_TIMEOUT = 60  # Read timeout in seconds
RETRY_BASE_DELAY = 2  # Base delay for exponential backoff
RETRY_MAX_DELAY = 60  # Maximum delay between retries
DEBUG_MODE = False  # Set to True to enable debug messages

# Global event for signaling cancellation between threads
cancellation_event = Event()

# Thread for checking for Ctrl+Z key press
def key_monitor():
    """Monitor for Ctrl+Z (ASCII 26) key press to cancel downloads"""
    while not cancellation_event.is_set():
        if msvcrt.kbhit():
            key = msvcrt.getch()
            # Check for Ctrl+Z (ASCII 26, or SUB character)
            if key == b'\x1a':
                print("\nCtrl+Z detected - Cancelling download and removing partial file...")
                cancellation_event.set()
                break
        time.sleep(0.1)  # Small sleep to prevent CPU hogging

def debug_print(message):
    """Print only if debug mode is enabled"""
    if DEBUG_MODE:
        print(message)

def format_size(size_bytes):
    """Format bytes into human-readable format"""
    if size_bytes >= 1_000_000_000:  # GB
        return f"{size_bytes / 1_000_000_000:.2f} GB"
    elif size_bytes >= 1_000_000:  # MB
        return f"{size_bytes / 1_000_000:.2f} MB"
    elif size_bytes >= 1000:  # KB
        return f"{size_bytes / 1000:.2f} KB"
    else:
        return f"{size_bytes} B"

def format_time(seconds):
    """Format seconds into HH:MM:SS format"""
    hours = seconds // 3600
    minutes = (seconds % 3600) // 60
    secs = seconds % 60
    if hours > 0:
        return f"{hours:02d}:{minutes:02d}:{secs:02d}"
    else:
        return f"{minutes:02d}:{secs:02d}"

def normalize_url(url):
    """
    Normalize URL by ensuring proper encoding of special characters
    while preserving URL structure
    """
    # Parse the URL into components
    parsed = urllib.parse.urlparse(url)
    
    # Split the path by '/' and encode each segment separately
    path_parts = parsed.path.split('/')
    encoded_parts = []
    
    for part in path_parts:
        # Dont double-encode already encoded segments, but ensure other parts are encoded
        if '%' in part and any(c.isalnum() for c in part.split('%')[1][:2]):
            encoded_parts.append(part)
        else:
            # Encode the part, preserving allowed characters
            encoded_parts.append(urllib.parse.quote(part, safe=''))
    
    # Reconstruct the path
    encoded_path = '/'.join(encoded_parts)
    
    # Build the URL with proper encoding
    normalized_url = urllib.parse.urlunparse((
        parsed.scheme,
        parsed.netloc,
        encoded_path,
        parsed.params,
        parsed.query,
        parsed.fragment
    ))
    
    return normalized_url

def get_file_size(url, headers):
    """Get the size of the file to be downloaded"""
    # First, make sure the URL is properly encoded
    normalized_url = normalize_url(url)
    
    for attempt in range(MAX_RETRIES):
        try:
            # Only get the headers, dont download the content yet
            response = requests.head(normalized_url, headers=headers, 
                                 timeout=(CONNECT_TIMEOUT, READ_TIMEOUT),
                                 allow_redirects=True)
            response.raise_for_status()
            
            # Return the content length if available
            content_length = response.headers.get('content-length')
            if content_length:
                return int(content_length)
            
            # If we cant get the size via HEAD request, return None
            return None
        
        except (requests.exceptions.RequestException, IOError) as e:
            delay = min(RETRY_BASE_DELAY * (2 ** attempt) + random.uniform(0, 1), RETRY_MAX_DELAY)
            if attempt < MAX_RETRIES - 1:
                debug_print(f"Error getting file size: {str(e)}. Retrying in {delay:.1f} seconds...")
                time.sleep(delay)
            else:
                debug_print(f"Failed to get file size after {MAX_RETRIES} attempts: {str(e)}")
                return None

def can_resume(url, headers):
    """Check if the server supports resuming downloads"""
    normalized_url = normalize_url(url)
    
    try:
        # Add range header to check if the server supports it
        resume_headers = headers.copy()
        resume_headers['Range'] = 'bytes=0-0'
        
        response = requests.head(normalized_url, headers=resume_headers, 
                             timeout=(CONNECT_TIMEOUT, READ_TIMEOUT),
                             allow_redirects=True)
        
        # If we get a 206 status, the server supports resume
        return response.status_code == 206
    except Exception as e:
        debug_print(f"Error checking resume capability: {str(e)}")
        # If theres any error, assume we cant resume to be safe
        return False

def download_file(url, destination, game_name, game_id, expected_size=None):
    """Download a file with progress tracking and resume support"""
    global cancellation_event
    cancellation_event.clear()  # Reset the cancellation event
    
    # Start key monitoring thread
    key_thread = Thread(target=key_monitor)
    key_thread.daemon = True
    key_thread.start()
    
    # Print information about stopping
    print("\nDownload started! Press Ctrl+Z to stop the download at any time.\n")
    
    headers = {
        "User-Agent": USER_AGENT,
        "Connection": "keep-alive",
        "Accept-Encoding": "gzip, deflate"
    }
    
    # Normalize the URL to handle special characters
    normalized_url = normalize_url(url)
    debug_print(f"Using normalized URL: {normalized_url}")
    
    # Get the file size if not provided
    total_size = expected_size
    if total_size is None:
        total_size = get_file_size(normalized_url, headers)

    # Check if we can resume
    supports_resume = can_resume(normalized_url, headers)
    debug_print(f"Server {'supports' if supports_resume else 'does not support'} resume capability.")
    
    # Check if the file already exists and if we should resume
    downloaded = 0
    if os.path.exists(destination) and supports_resume:
        downloaded = os.path.getsize(destination)
        if total_size and downloaded >= total_size:
            print(f"\nFile already completely downloaded: {destination}")
            cancellation_event.set()  # Signal to stop key monitor thread
            return True
        elif downloaded > 0:
            print(f"\nResuming download from {format_size(downloaded)}")
            headers['Range'] = f'bytes={downloaded}-'
    
    # Prepare for progress tracking
    start_time = time.time()
    init_downloaded = downloaded  # Keep the initial download amount for speed calculation
    last_update_time = start_time
    last_downloaded = downloaded  # For calculating current download speed
    
    # Setup for retrying connection
    for attempt in range(MAX_RETRIES):
        # Check if download was cancelled by user
        if cancellation_event.is_set():
            print("\nDownload cancelled by user. Removing partial file...")
            try:
                if os.path.exists(destination):
                    os.remove(destination)
                    print(f"Partial file deleted successfully.")
            except Exception as e:
                print(f"Note: Could not delete partial file: {str(e)}")
            return False
        
        try:
            # Open the file in append mode if resuming, otherwise write mode
            file_mode = 'ab' if downloaded > 0 else 'wb'
            
            with requests.get(normalized_url, headers=headers, stream=True, 
                             timeout=(CONNECT_TIMEOUT, READ_TIMEOUT),
                             allow_redirects=True) as response:
                response.raise_for_status()
                
                # If we requested a range but got the whole file, adjust our counter
                if downloaded > 0 and response.status_code != 206:
                    debug_print("Warning: Server doesnt support resuming. Starting from beginning.")
                    downloaded = 0
                    file_mode = 'wb'
                
                # Update total_size if we can get it from headers
                if total_size is None and 'content-length' in response.headers:
                    total_size = int(response.headers['content-length']) + downloaded
                
                print(f"[Download Progress - {game_name} ({game_id})]")
                
                with open(destination, file_mode) as f:
                    for chunk in response.iter_content(chunk_size=CHUNK_SIZE):
                        # Check for cancellation
                        if cancellation_event.is_set():
                            print("\nDownload cancelled by user. Removing partial file...")
                            f.close()  # Close file handle before deleting
                            try:
                                os.remove(destination)
                                print(f"Partial file deleted successfully.")
                            except Exception as e:
                                print(f"Note: Could not delete partial file: {str(e)}")
                            return False
                            
                        if chunk:
                            f.write(chunk)
                            downloaded += len(chunk)
                            current_time = time.time()
                            
                            # Update progress every 0.5 seconds
                            if (current_time - last_update_time) >= 0.5:
                                last_update_time = current_time
                                
                                # Calculate progress values
                                elapsed_time = current_time - start_time
                                elapsed_seconds = int(elapsed_time)
                                progress_percent = int((downloaded / total_size) * 100) if total_size and total_size > 0 else 0
                                
                                # Calculate overall average speed
                                avg_download_speed = (downloaded - init_downloaded) / elapsed_time if elapsed_time > 0 else 0
                                avg_download_speed_mbps = avg_download_speed * 8 / 1024 / 1024  # Convert to Mbps
                                
                                # Calculate current window speed (last 0.5 seconds)
                                current_window_size = downloaded - last_downloaded
                                current_speed = current_window_size / (current_time - last_update_time + 0.001)
                                current_speed_mbps = current_speed * 8 / 1024 / 1024  # Convert to Mbps
                                last_downloaded = downloaded
                                
                                # Calculate remaining time based on average speed
                                remaining_bytes = total_size - downloaded if total_size else 0
                                if avg_download_speed > 0 and remaining_bytes > 0:
                                    remaining_seconds = int(remaining_bytes / avg_download_speed)
                                else:
                                    remaining_seconds = 0
                                
                                # Simple output - replace previous line with new status
                                # Carriage return to move cursor to beginning of line
                                sys.stdout.write("\r" + " " * 80 + "\r")  # Clear line
                                
                                # Print progress information
                                if total_size and total_size > 0:
                                    prog_str = f"Progress: {progress_percent}% | "
                                else:
                                    prog_str = ""
                                
                                # Show actual progress info
                                size_info = f"of {format_size(total_size)}" if total_size else ""
                                status = f"{prog_str}Downloaded: {format_size(downloaded)} {size_info} | Speed: {avg_download_speed_mbps:.2f} Mbps"
                                sys.stdout.write(status)
                                sys.stdout.flush()
            
            # Final update
            elapsed_time = time.time() - start_time
            elapsed_seconds = int(elapsed_time)
            avg_download_speed = (downloaded - init_downloaded) / elapsed_time if elapsed_time > 0 else 0
            avg_download_speed_mbps = avg_download_speed * 8 / 1024 / 1024
            
            # Print final stats on new lines
            print("\n\nDownload completed successfully!")
            print(f"Total Size: {format_size(downloaded)}")
            print(f"Average Speed: {avg_download_speed_mbps:.2f} Mbps")
            print(f"Time Elapsed: {format_time(elapsed_seconds)}")
            
            # Signal to stop key monitor thread
            cancellation_event.set()
            return True
            
        except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e:
            # Handle connection timeout with exponential backoff retry
            if cancellation_event.is_set():
                print("\nDownload cancelled by user. Removing partial file...")
                try:
                    if os.path.exists(destination):
                        os.remove(destination)
                        print(f"Partial file deleted successfully.")
                except Exception as e:
                    print(f"Note: Could not delete partial file: {str(e)}")
                return False
                
            delay = min(RETRY_BASE_DELAY * (2 ** attempt) + random.uniform(0, 1), RETRY_MAX_DELAY)
            if attempt < MAX_RETRIES - 1:
                print(f"\nConnection timed out or lost: {str(e)}. Retrying in {delay:.1f} seconds...")
                print(f"Downloaded so far: {format_size(downloaded)}")
                time.sleep(delay)
                # Update headers for resuming from the current position
                headers['Range'] = f'bytes={downloaded}-'
                last_update_time = time.time()  # Reset the update timer
                # Print a new header for the next attempt
                print(f"\n[Download Progress - {game_name} ({game_id}) - Attempt {attempt+2}]")
            else:
                print(f"\nDownload failed after {MAX_RETRIES} attempts: {str(e)}")
                print(f"Note: Partial file will be removed.")
                try:
                    if os.path.exists(destination):
                        os.remove(destination)
                        print(f"Partial file deleted successfully.")
                except Exception as ex:
                    print(f"Note: Could not delete partial file: {str(ex)}")
                cancellation_event.set()  # Signal to stop key monitor thread
                return False
            
        except requests.exceptions.RequestException as e:
            # Handle other request exceptions
            if cancellation_event.is_set():
                print("\nDownload cancelled by user. Removing partial file...")
                try:
                    if os.path.exists(destination):
                        os.remove(destination)
                        print(f"Partial file deleted successfully.")
                except Exception as e:
                    print(f"Note: Could not delete partial file: {str(e)}")
                return False
                
            if attempt < MAX_RETRIES - 1:
                delay = min(RETRY_BASE_DELAY * (2 ** attempt) + random.uniform(0, 1), RETRY_MAX_DELAY)
                print(f"\nDownload error: {str(e)}. Retrying in {delay:.1f} seconds...")
                time.sleep(delay)
                # Update headers for resuming from the current position
                headers['Range'] = f'bytes={downloaded}-'
                last_update_time = time.time()
                # Print a new header for the next attempt
                print(f"\n[Download Progress - {game_name} ({game_id}) - Attempt {attempt+2}]")
            else:
                print(f"\nDownload failed after {MAX_RETRIES} attempts: {str(e)}")
                print(f"Note: Partial file will be removed.")
                try:
                    if os.path.exists(destination):
                        os.remove(destination)
                        print(f"Partial file deleted successfully.")
                except Exception as ex:
                    print(f"Note: Could not delete partial file: {str(ex)}")
                cancellation_event.set()  # Signal to stop key monitor thread
                return False
        
        except IOError as e:
            # Handle file I/O errors
            print(f"\nFile I/O error: {str(e)}")
            print(f"Note: Partial file will be removed.")
            try:
                if os.path.exists(destination):
                    os.remove(destination)
                    print(f"Partial file deleted successfully.")
            except Exception as ex:
                print(f"Note: Could not delete partial file: {str(ex)}")
            cancellation_event.set()  # Signal to stop key monitor thread
            return False
    
    cancellation_event.set()  # Signal to stop key monitor thread
    return False

def main():
    """Main entry point for the script"""
    # Check if we have enough arguments
    if len(sys.argv) < 5:
        print("Usage: python ccls_downloader.py <download_url> <output_file> <game_name> <game_id> [<total_size_bytes>]")
        return 1
    
    try:
        download_url = sys.argv[1]
        output_file = sys.argv[2]
        game_name = sys.argv[3]
        game_id = sys.argv[4]
        
        debug_print(f"Download URL: {download_url}")
        debug_print(f"Output file: {output_file}")
        debug_print(f"Item name: {game_name}")
        debug_print(f"Item ID: {game_id}")
        
        # Optional size parameter
        expected_size = None
        if len(sys.argv) > 5:
            try:
                expected_size = int(sys.argv[5])
                debug_print(f"Expected size: {format_size(expected_size)}")
            except ValueError:
                debug_print(f"Warning: Invalid size parameter '{sys.argv[5]}', will use content-length from server")
        
        # Create output directory if it doesnt exist
        output_dir = os.path.dirname(output_file)
        if output_dir and not os.path.exists(output_dir):
            try:
                os.makedirs(output_dir)
                debug_print(f"Created output directory: {output_dir}")
            except Exception as e:
                print(f"Error: Could not create directory: {str(e)}")
                return 1
        
        # Start download
        result = download_file(download_url, output_file, game_name, game_id, expected_size)
        
        # Return success or failure code
        return 0 if result else 1
        
    except Exception as e:
        print(f"Error: Unexpected error: {str(e)}")
        if DEBUG_MODE:
            import traceback
            traceback.print_exc()
        return 1

if __name__ == "__main__":
    try:
        sys.exit(main())
    except KeyboardInterrupt:
        # This shouldnt be reached now that we use our own key handler
        print("\nKeyboard interrupt detected.")
        sys.exit(1)
'@
            
            Set-Content -Path $pythonScript -Value $pythonCode -Encoding UTF8
            
            # If we have Python and the downloader script, use it
            if ($pythonAvailable -and (Test-Path $pythonScript)) {
                Write-CCLSHost "#Using Python high-speed downloader" -Log -NoConsole
                
                # Convert the item size to bytes if possible (for progress calculation)
                $sizeInBytes = $null
                if ($itemSize -match "(\d+\.?\d*)\s*(GB|MB|KB|B)") {
                    $value = [double]$matches[1]
                    $unit = $matches[2]
                    
                    switch ($unit) {
                        "GB" { $sizeInBytes = [math]::Round($value * 1GB) }
                        "MB" { $sizeInBytes = [math]::Round($value * 1MB) }
                        "KB" { $sizeInBytes = [math]::Round($value * 1KB) }
                        "B"  { $sizeInBytes = [math]::Round($value) }
                    }
                }
                
                try {
                    # Build the command line with proper quoting
                    $argList = @()
                    $argList += "`"$pythonScript`""
                    $argList += "`"$downloadUrl`""
                    $argList += "`"$downloadPath`""
                    $argList += "`"$itemName`""
                    $argList += "`"$itemId`""
                    
                    if ($sizeInBytes) {
                        $argList += "$sizeInBytes"
                    }
                    
                    $commandLine = "python $($argList -join ' ')"
                    Write-CCLSHost "#Running command: $commandLine" -Log -NoConsole
                    
                    # Run Python as a normal process without redirecting output
                    # This allows it to directly handle console output
                    $process = Start-Process python -ArgumentList $argList -NoNewWindow -PassThru -Wait
                    
                    if ($process.ExitCode -ne 0) {
                        # Check if a partial file exists and delete it
                        if (Test-Path $downloadPath) {
                            Write-CCLSHost "Download was cancelled. Removing partial file..." -ForegroundColor Yellow -Log
                            try {
                                Remove-Item -Path $downloadPath -Force
                                Write-CCLSHost "Partial file removed successfully." -ForegroundColor Yellow -Log
                            } catch {
                                Write-CCLSHost "Note: Could not remove partial file: $($_.Exception.Message)" -ForegroundColor Yellow -Log
                            }
                        } else {
                            Write-CCLSHost "Download was cancelled." -ForegroundColor Yellow -Log
                        }
                        
                        # Return early without attempting extraction
                        return
                    }
                    
                    # If we got here, download was successful
                    $downloadSuccessful = $true
                }
                catch {
                    Write-CCLSHost "Error running Python downloader: $($_.Exception.Message)" -ForegroundColor Red -Log -NoConsole
                    Write-CCLSHost "#Falling back to PowerShell download method" -Log -NoConsole
                    $downloadSuccessful = Use-PowerShellDownload -downloadUrl $downloadUrl -downloadPath $downloadPath -gameName $itemName -gameId $itemId
                }
            }
            else {
                # Fall back to the original PowerShell download method
                Write-CCLSHost "#Python downloader not available, using PowerShell download method" -Log -NoConsole
                $downloadSuccessful = Use-PowerShellDownload -downloadUrl $downloadUrl -downloadPath $downloadPath -gameName $itemName -gameId $itemId
            }
        } 
        catch {
            $pythonAvailable = $false
            Write-CCLSHost "#Python not found, falling back to PowerShell download method" -Log -NoConsole
            $downloadSuccessful = Use-PowerShellDownload -downloadUrl $downloadUrl -downloadPath $downloadPath -gameName $itemName -gameId $itemId
        }
        
        # Only proceed with extraction and info saving if download was successful
        if ($downloadSuccessful) {
            # This variable will hold the extracted folder path
            $extractedFolderPath = $null
            
            # Start extraction process
            Write-CCLSHost "#Starting extraction process..." -Log -NoConsole
            
            try {
                # Define the self-contained extraction function
                function Start-GameExtraction {
                    # Load settings independently (similar to ass.ps1 but with adjusted path)
                    $scriptPath = $settingsFolder
                    $settingsPath = Join-Path -Path $scriptPath -ChildPath "settings.json"
                    
                    Write-CCLSHost "#Loading settings from: $settingsPath" -Log -NoConsole
                    
                    # Check if settings file exists
                    if (-not (Test-Path -Path $settingsPath)) {
                        Write-CCLSHost "Error: Settings file not found at '$settingsPath'." -ForegroundColor Red -Log
                        return
                    }
                    
                    # Load and parse the settings.json file
                    $extractSettings = Get-Content -Path $settingsPath -ErrorAction Stop | ConvertFrom-Json
                    
                    # Get paths from settings
                    $tempDownloadPath = $extractSettings.TempDownloadPath
                    $downloadPath = $extractSettings.DownloadPath
                    
                    Write-CCLSHost "#Loaded TempDownloadPath: $tempDownloadPath" -Log -NoConsole
                    Write-CCLSHost "#Loaded DownloadPath: $downloadPath" -Log -NoConsole
                    
                    # Verify paths exist
                    if (-not (Test-Path -Path $tempDownloadPath)) {
                        Write-CCLSHost "Error: TempDownloadPath '$tempDownloadPath' does not exist." -ForegroundColor Red -Log
                        return
                    }
                    
                    if (-not (Test-Path -Path $downloadPath)) {
                        Write-CCLSHost "Error: DownloadPath '$downloadPath' does not exist." -ForegroundColor Red -Log
                        return
                    }
                    
                    # Check if 7-Zip is installed
                    $7zipPath = "C:\Program Files\7-Zip\7z.exe"
                    if (-not (Test-Path -Path $7zipPath)) {
                        # Try alternative paths
                        $alternativePaths = @(
                            "${env:ProgramFiles(x86)}\7-Zip\7z.exe",
                            ".\7zip\7z.exe"
                        )
                        
                        $found = $false
                        foreach ($path in $alternativePaths) {
                            if (Test-Path -Path $path) {
                                $7zipPath = $path
                                $found = $true
                                break
                            }
                        }
                        
                        if (-not $found) {
                            Write-CCLSHost "Error: 7-Zip is not installed at any expected location." -ForegroundColor Red -Log
                            Write-CCLSHost "Please install 7-Zip using the 'install 7zip' command." -ForegroundColor Yellow -Log
                            Write-CCLSHost "Once you have installed 7zip run 'extract [cb/cg id] -y' to extract the game" -ForegroundColor Yellow -Log
                            return
                        }
                    }
                    
                    # Get all .7z files in the temp download path
                    Write-CCLSHost "#Searching for .7z files in: $tempDownloadPath" -Log -NoConsole
                    $7zFiles = Get-ChildItem -Path $tempDownloadPath -Filter "*.7z"
                    
                    # If no .7z files found, exit
                    if ($7zFiles.Count -eq 0) {
                        Write-CCLSHost "No .7z files found in '$tempDownloadPath'." -ForegroundColor Yellow -Log
                        return
                    }
                    
                    Write-CCLSHost "#Found $($7zFiles.Count) .7z files to process." -Log -NoConsole
                    
                    # Variable to return the extracted folder path
                    $script:extractedFolderPath = $downloadPath
                    
                    # Process each .7z file
                    foreach ($file in $7zFiles) {
                        $filePath = $file.FullName
                        
                        # Extract the file
                        Write-CCLSHost "Extracting: $filePath to $downloadPath" -ForegroundColor Cyan -Log
                        
                        # Capture and suppress 7-Zip output, only show errors if extraction fails
                        $extractionOutput = & "$7zipPath" x "$filePath" -o"$downloadPath" -y 2>&1
                        $extractionSuccess = $?
                        
                        # Check if extraction was successful
                        if ($extractionSuccess -and $LASTEXITCODE -eq 0) {
                            # Delete the original .7z file
                            Write-CCLSHost "Extraction successful. Deleting original file: $filePath" -ForegroundColor Green -Log
                            Remove-Item -Path $filePath -Force
                            
                            # Return to the main context that extraction was successful
                            $script:extractionStatus = $true
                        } else {
                            Write-CCLSHost "Failed to extract: $filePath. Skipping deletion." -ForegroundColor Red -Log
                            $script:extractionStatus = $false
                        }
                    }
                    
                    Write-CCLSHost "#All .7z files have been processed." -Log -NoConsole
                    Write-CCLSHost "#Go to $downloadPath to access the $itemType." -ForegroundColor Cyan -Log -NoConsole
                    
                    # Return the path
                    return $script:extractedFolderPath
                }
                
                # Call the extraction function
                $script:extractionStatus = $false
                $script:extractedFolderPath = $null
                Start-GameExtraction
                
                # After extraction, save the game info JSON
                if ($script:extractionStatus -and $script:extractedFolderPath) {
                    # Get a cleaned item name for the folder name
                    $cleanedItemName = $itemName -replace '[\\/:*?"<>|]', '_'
                    
                    # Create a folder for the item if it doesn't exist already
                    $itemFolderPath = Join-Path -Path $script:extractedFolderPath -ChildPath $cleanedItemName
                    if (-not (Test-Path $itemFolderPath) -and (Test-Path $script:extractedFolderPath)) {
                        # Look for any folder that might have been created by the extraction
                        $extractedFolders = Get-ChildItem -Path $script:extractedFolderPath -Directory
                        if ($extractedFolders.Count -gt 0) {
                            # Use the first extracted folder as item folder
                            $itemFolderPath = $extractedFolders[0].FullName
                            Write-CCLSHost "#Using extracted folder: $itemFolderPath" -Log -NoConsole
                        } else {
                            # If no folders found, use the base download path
                            $itemFolderPath = $script:extractedFolderPath
                            Write-CCLSHost "#No specific folder found for the item, using: $itemFolderPath" -Log -NoConsole
                        }
                    }
                    
                    # Path for the info JSON file
                    $infoJsonPath = Join-Path -Path $itemFolderPath -ChildPath "$itemId.json"
                    
                    # Save item info to JSON file
                    try {
                        $itemInfo | ConvertTo-Json -Depth 10 | Set-Content -Path $infoJsonPath -Encoding UTF8
                        Write-CCLSHost "#Saved game information to: $infoJsonPath" -ForegroundColor Green -Log -NoConsole
                    } catch {
                        Write-CCLSHost "Error saving game information: $($_.Exception.Message)" -ForegroundColor Red -Log
                    }
                }
            }
            catch {
                Write-CCLSHost "An error occurred during extraction: $($_.Exception.Message)" -ForegroundColor Red -Log
            }
        }
    }
    catch {
        Write-CCLSHost "An error occurred: $($_.Exception.Message)" -ForegroundColor Red -Log
    }
}

# Helper function for PowerShell download (used as fallback if Python fails)
function Use-PowerShellDownload {
    param (
        [string]$downloadUrl,
        [string]$downloadPath,
        [string]$gameName,
        [string]$gameId
    )
    
    try {
        Write-CCLSHost "Python downloader failed..." -ForegroundColor Red -Log
        Write-CCLSHost "Downloading using PowerShell method..." -ForegroundColor Cyan -Log
        Write-CCLSHost "Bandwidth might be limited due to Powershell API constraints" -ForegroundColor Cyan -Log
        
        # Create a WebClient object for downloading
        $webClient = New-Object System.Net.WebClient
        $webClient.Headers.Add("User-Agent", "CCLS-CLI/1.0")
        
        # Set up progress tracking
        $totalBytes = 0
        $receivedBytes = 0
        $tempFile = "$downloadPath.tmp"
        
        # Set up the event handlers
        try {
            # Create event handlers for download progress
            $script:startTime = $null
            $script:downloadComplete = $false
            
            # Use Add_DownloadProgressChanged instead of DownloadProgressChanged property
            $webClient.Add_DownloadProgressChanged({
                param($sender, $e)
                
                $receivedBytes = $e.BytesReceived
                $totalBytes = $e.TotalBytesToReceive
                $progressPercentage = $e.ProgressPercentage
                
                # Calculate download speed
                $currentTime = Get-Date
                if ($script:startTime -eq $null) { $script:startTime = $currentTime }
                $timeSpan = New-TimeSpan -Start $script:startTime -End $currentTime
                $downloadSpeed = 0
                if ($timeSpan.TotalSeconds -gt 0) {
                    $downloadSpeed = $receivedBytes / $timeSpan.TotalSeconds / 1MB
                }
                
                # Format the display values
                $receivedMB = "{0:N2}" -f ($receivedBytes / 1MB)
                $totalMB = "{0:N2}" -f ($totalBytes / 1MB)
                $speedDisplay = "{0:N2}" -f $downloadSpeed
                
                # Clear the current line and display new progress
                Write-Host "`r                                                                       " -NoNewline
                Write-Host "`rProgress: $progressPercentage% ($receivedMB MB / $totalMB MB) Speed: $speedDisplay MB/s" -NoNewline
            })
            
            # Use Add_DownloadFileCompleted instead of DownloadFileCompleted property
            $webClient.Add_DownloadFileCompleted({
                param($sender, $e)
                
                if ($e.Error -ne $null) {
                    Write-CCLSHost "`nDownload failed: $($e.Error.Message)" -ForegroundColor Red -Log
                }
                elseif ($e.Cancelled) {
                    Write-CCLSHost "`nDownload cancelled." -ForegroundColor Yellow -Log
                }
                else {
                    # Download completed successfully, move temp file
                    if (Test-Path $tempFile) {
                        if (Test-Path $downloadPath) { Remove-Item $downloadPath -Force }
                        Rename-Item -Path $tempFile -NewName (Split-Path $downloadPath -Leaf) -Force
                    }
                    
                    Write-CCLSHost "`nDownload completed successfully!" -ForegroundColor Green -Log
                }
                
                # Signal completion
                $script:downloadComplete = $true
            })
        }
        catch {
            Write-CCLSHost "#Error setting up event handlers: $($_.Exception.Message)" -ForegroundColor Red -Log -NoConsole
            # If we can't use event handlers, we'll use a simpler approach
            try {
                $webClient.DownloadFile($downloadUrl, $downloadPath)
                Write-CCLSHost "Download completed!" -ForegroundColor Green -Log
                return $true
            }
            catch {
                Write-CCLSHost "Download failed: $($_.Exception.Message)" -ForegroundColor Red -Log
                return $false
            }
        }
        
        Write-CCLSHost "Starting download of $gameName ($gameId)..." -ForegroundColor Cyan -Log
        
        # Reset tracking variables
        $script:startTime = $null
        $script:downloadComplete = $false
        
        # Start asynchronous download
        $webClient.DownloadFileAsync((New-Object System.Uri($downloadUrl)), $tempFile)
        
        # Wait for download to complete
        while (-not $script:downloadComplete) {
            Start-Sleep -Milliseconds 500
            
            # Check for cancellation (Ctrl+Z)
            if ([Console]::KeyAvailable) {
                $key = [Console]::ReadKey($true)
                if ($key.Key -eq [ConsoleKey]::Z -and $key.Modifiers -eq [ConsoleModifiers]::Control) {
                    Write-CCLSHost "`nCtrl+Z detected - Cancelling download..." -ForegroundColor Yellow -Log
                    $webClient.CancelAsync()
                    break
                }
            }
        }
        
        # Clean up
        $webClient.Dispose()
        
        # Return status
        return ($script:downloadComplete -and (Test-Path $downloadPath))
    }
    catch {
        Write-CCLSHost "PowerShell download error: $($_.Exception.Message)" -ForegroundColor Red -Log -NoConsole
        return $false
    }
}

# Function to check system requirements
function Test-SystemRequirements {
    Write-CCLSHost "Checking system requirements:" -ForegroundColor Cyan -Log
    
    # Check for Python
    Write-CCLSHost "Python           : " -NoNewline -Log
    try {
        $pythonResult = python --version 2>&1
        if ($pythonResult -match "Python (\d+\.\d+\.\d+)") {
            $pythonVersion = $matches[1]
            Write-CCLSHost "Installed (v$pythonVersion)" -ForegroundColor Green -Log
            $pythonInstalled = $true
        } else {
            Write-CCLSHost "Not detected" -ForegroundColor Red -Log
            $pythonInstalled = $false
        }
    } catch {
        Write-CCLSHost "Not installed" -ForegroundColor Red -Log
        $pythonInstalled = $false
    }
    
    # Check for Python requests library (only if Python is installed)
    Write-CCLSHost "Python requests  : " -NoNewline -Log
    if ($pythonInstalled) {
        try {
            $requestsCheck = python -c "import requests; print('Installed (v{0})'.format(requests.__version__))" 2>&1
            if ($requestsCheck -match "Installed \(v([\d\.]+)\)") {
                $requestsVersion = $matches[1]
                Write-CCLSHost "Installed (v$requestsVersion)" -ForegroundColor Green -Log
            } else {
                Write-CCLSHost "Not installed" -ForegroundColor Red -Log
            }
        } catch {
            Write-CCLSHost "Not installed" -ForegroundColor Red -Log
        }
    } else {
        Write-CCLSHost "Not applicable (Python not installed)" -ForegroundColor Yellow -Log
    }
    
    # Check for 7-Zip
    Write-CCLSHost "7-Zip            : " -NoNewline -Log
    
    # Check system-wide 7-Zip installation
    $systemPaths = @(
        "C:\Program Files\7-Zip\7z.exe",
        "${env:ProgramFiles(x86)}\7-Zip\7z.exe"
    )
    
    # Check local 7-Zip installation
    $scriptLocation = if ($PSScriptRoot) {
        $PSScriptRoot
    } else {
        (Get-Location).Path
    }
    $localPath = Join-Path -Path $scriptLocation -ChildPath "7zip\7z.exe"
    
    # Combine all paths to check
    $allPaths = $systemPaths + $localPath
    
    $7zipInstalled = $false
    $7zipLocation = ""
    
    foreach ($path in $allPaths) {
        if (Test-Path -Path $path) {
            $7zipInstalled = $true
            $7zipLocation = $path
            break
        }
    }
    
    if ($7zipInstalled) {
        # Get 7-Zip version
        try {
            $versionInfo = Get-Item $7zipLocation | Select-Object -ExpandProperty VersionInfo
            $7zipVersion = $versionInfo.ProductVersion
            Write-CCLSHost "Installed (v$7zipVersion)" -ForegroundColor Green -Log
        } catch {
            Write-CCLSHost "Installed (unknown version)" -ForegroundColor Green -Log
        }
    } else {
        Write-CCLSHost "Not installed" -ForegroundColor Red -Log
    }
    
    # Summary of checks
    Write-CCLSHost "`nSystem Check Summary:" -ForegroundColor Cyan -Log
    if (-not $pythonInstalled) {
        Write-CCLSHost "  - Python is not installed. Python enables faster downloads with resumable transfers." -ForegroundColor Yellow -Log
        Write-CCLSHost "    Download from: https://www.python.org/downloads/" -ForegroundColor Yellow -Log
    }
    
    if ($pythonInstalled -and $requestsCheck -notmatch "Installed") {
        Write-CCLSHost "  - Python 'requests' library is not installed." -ForegroundColor Yellow -Log
        Write-CCLSHost "    Install with: install requests" -ForegroundColor Yellow -Log
    }
    
    if (-not $7zipInstalled) {
        Write-CCLSHost "  - 7-Zip is not installed. 7-Zip is required for extracting downloaded games." -ForegroundColor Yellow -Log
        Write-CCLSHost "    Install with: install 7zip" -ForegroundColor Yellow -Log
    }
    
    if ($pythonInstalled -and $requestsCheck -match "Installed" -and $7zipInstalled) {
        Write-CCLSHost "All system requirements are met. Your system is ready to use all features." -ForegroundColor Green -Log
    }
}

# Get-GamesList function that uses the cached credentials
function Get-GamesList {
    # Check if credentials are cached
    if ($null -eq $script:cachedCredentials) {
        Write-CCLSHost "Error: Not logged in. Please restart the application and log in." -ForegroundColor Red -Log
        return
    }
    
    try {
        # Set up request parameters with credentials
        $params = @{
            Uri = "$cliApiUrl/list.php"
            Method = "POST"
            Headers = @{
                "User-Agent" = "CCLS-CLI/1.0"
            }
            Body = @{
                username = $script:cachedCredentials.Username
                password = $script:cachedCredentials.Password
            }
        }
        
        Write-CCLSHost "#Fetching game and bundle library..." -Log
        
        # Fetch library from server
        try {
            $response = Invoke-RestMethod @params
            
            # Check if the request was successful
            if (-not $response.success) {
                Write-CCLSHost "Error: $($response.message)" -ForegroundColor Red -Log
                return
            }
            
            # Display game list
            Write-CCLSHost "==========================================================" -ForegroundColor DarkGray -Log
            Write-CCLSHost "Game Library - $($response.count) games available" -ForegroundColor Green -Log
            Write-CCLSHost "==========================================================" -ForegroundColor DarkGray -Log
            
            if ($response.count -eq 0) {
                Write-CCLSHost "No games found in the library." -ForegroundColor Yellow -Log
            }
            else {
                # Determine the maximum length for proper formatting
                $maxNameLength = ($response.games | ForEach-Object { $_.name.Length } | Measure-Object -Maximum).Maximum
                $maxIdLength = ($response.games | ForEach-Object { $_.id.Length } | Measure-Object -Maximum).Maximum
                
                # Ensure minimum column widths
                $nameColumnWidth = [Math]::Max($maxNameLength, 30)
                $idColumnWidth = [Math]::Max($maxIdLength, 8)
                
                # Create header
                Write-CCLSHost "$("Game Name".PadRight($nameColumnWidth)) => $("CG Number".PadRight($idColumnWidth))" -ForegroundColor Cyan -Log
                Write-CCLSHost "$("-" * $nameColumnWidth) => $("-" * $idColumnWidth)" -ForegroundColor Cyan -Log
                
                # Print each game with proper formatting
                foreach ($game in $response.games) {
                    Write-CCLSHost "$($game.name.PadRight($nameColumnWidth)) => $($game.id)" -ForegroundColor White -Log
                }
            }
            
            # Display bundle list if any bundles exist
            if ($response.bundle_count -gt 0) {
                Write-CCLSHost "`n==========================================================" -ForegroundColor DarkGray -Log
                Write-CCLSHost "Bundle Library - $($response.bundle_count) bundles available" -ForegroundColor Green -Log
                Write-CCLSHost "==========================================================" -ForegroundColor DarkGray -Log
                
                # Determine the maximum length for proper formatting
                $maxNameLength = ($response.bundles | ForEach-Object { $_.name.Length } | Measure-Object -Maximum).Maximum
                $maxIdLength = ($response.bundles | ForEach-Object { $_.id.Length } | Measure-Object -Maximum).Maximum
                
                # Ensure minimum column widths
                $nameColumnWidth = [Math]::Max($maxNameLength, 30)
                $idColumnWidth = [Math]::Max($maxIdLength, 8)
                
                # Create header
                Write-CCLSHost "$("Bundle Name".PadRight($nameColumnWidth)) => $("CB Number".PadRight($idColumnWidth))" -ForegroundColor Cyan -Log
                Write-CCLSHost "$("-" * $nameColumnWidth) => $("-" * $idColumnWidth)" -ForegroundColor Cyan -Log
                
                # Print each bundle with proper formatting
                foreach ($bundle in $response.bundles) {
                    Write-CCLSHost "$($bundle.name.PadRight($nameColumnWidth)) => $($bundle.id)" -ForegroundColor White -Log
                }
            }
            
            Write-CCLSHost "`nUse 'search [cgnumber/cbnumber]' to get detailed information about a specific game or bundle." -ForegroundColor Yellow -Log
        }
        catch {
            Write-CCLSHost "Error fetching library: $($_.Exception.Message)" -ForegroundColor Red -Log
        }
    }
    catch {
        Write-CCLSHost "An error occurred while processing library: $($_.Exception.Message)" -ForegroundColor Red -Log
    }
}

# Main CLI interface
function Start-MainInterface($username) {
    Write-CCLSHost "`n`nWelcome to CCLS Games CLI Tool, $username!" -ForegroundColor Green -Log
    
    # Load settings to check setup status
    $settings = Initialize-Settings
    $versionCheckResult = Test-VersionUpdate
    
    # Show appropriate message based on setup status
    if ($settings.HasCompletedSetup) {
        Write-CCLSHost "Type 'help' for a list of available commands.`n" -ForegroundColor Cyan -Log
    }
    else {
        Write-CCLSHost "ALERT, type command 'setup' to set critical values before downloading." -ForegroundColor Red -Log
    }
}

function Clear-ConsoleScreen {
    # Log the clear command
    Write-CCLSHost "#User cleared the console screen" -Log -NoConsole

    # Use the PowerShell Clear-Host cmdlet to clear the console
    Clear-Host
}

# Function to get folder size including subfolders
function Get-FolderSize {
    param (
        [string]$Path
    )
    
    $totalSize = 0
    
    try {
        # Get all files in the folder and subfolders
        $files = Get-ChildItem -Path $Path -Recurse -File -ErrorAction SilentlyContinue
        foreach ($file in $files) {
            $totalSize += $file.Length
        }
    }
    catch {
        Write-CCLSHost "Error calculating folder size: $($_.Exception.Message)" -ForegroundColor Red -Log
    }
    
    return $totalSize
}

# Modified function to list games with version information
function Get-InstalledGames {
    param (
        [switch]$Detailed
    )
    
    # Get settings to find download directory
    $settings = Initialize-Settings
    $downloadPath = $settings.DownloadPath
    
    # Check if download path exists
    if (-not (Test-Path $downloadPath)) {
        Write-CCLSHost "Downloads folder does not exist yet. No games are installed." -ForegroundColor Yellow -Log
        return
    }
    
    # Get all folders in the download path
    try {
        $gameFolders = Get-ChildItem -Path $downloadPath -Directory
        
        # If no games found
        if ($gameFolders.Count -eq 0) {
            Write-CCLSHost "No games found in $downloadPath" -ForegroundColor Yellow -Log
            return
        }
        
        # Header
        Write-CCLSHost "`nInstalled Games" -ForegroundColor Green -Log
        Write-CCLSHost "==============" -ForegroundColor Green -Log
        
        # Calculate total size if detailed view
        $totalSize = 0
        
        # List each game
        foreach ($folder in $gameFolders) {
            # Get folder size
            $size = Get-FolderSize -Path $folder.FullName
            $totalSize += $size
            $sizeFormatted = Format-Size -Size $size
            
            if ($Detailed) {
                # Look for JSON files with game info
                $jsonFiles = Get-ChildItem -Path $folder.FullName -Filter "*.json" -Recurse | Where-Object { $_.Name -match "^c[gb]\d{4}\.json$" }
                
                $version = "Unknown"
                $isOutdated = $false
                $gameId = $null
                
                if ($jsonFiles.Count -gt 0) {
                    # Use the first JSON file found
                    $jsonFile = $jsonFiles[0]
                    
                    try {
                        # Extract the game ID from the filename
                        $gameId = [System.IO.Path]::GetFileNameWithoutExtension($jsonFile.Name)
                        
                        # Load the JSON file
                        $gameInfo = Get-Content -Path $jsonFile.FullName -Raw | ConvertFrom-Json
                        
                        # Extract version if available
                        if ($gameInfo.version) {
                            $version = $gameInfo.version
                        }
                        
                        # Check if credentials are cached for server check
                        if ($null -ne $script:cachedCredentials -and 
                            $null -ne $script:cachedCredentials.Username -and 
                            $null -ne $script:cachedCredentials.Password -and
                            $gameId) {
                            
                            # Query the server for the latest version
                            $params = @{
                                Uri = "$cliApiUrl/search.php"
                                Method = "POST"
                                Headers = @{
                                    "User-Agent" = "CCLS-CLI/1.0"
                                }
                                Body = @{
                                    username = $script:cachedCredentials.Username
                                    password = $script:cachedCredentials.Password
                                    id = $gameId
                                }
                            }
                            
                            Write-CCLSHost "#Checking for updates for $gameId..." -Log -NoConsole
                            
                            $response = Invoke-RestMethod @params
                            
                            if ($response.success -and $response.version) {
                                $latestVersion = $response.version
                                
                                # Compare versions
                                if ($version -ne $latestVersion -and $version -ne "Unknown" -and $latestVersion -ne "") {
                                    $isOutdated = $true
                                    Write-CCLSHost "#Game $($folder.Name) is outdated. Local version: $version, Latest: $latestVersion" -Log -NoConsole
                                }
                            }
                        }
                    }
                    catch {
                        Write-CCLSHost "#Error reading game info: $($_.Exception.Message)" -Log -NoConsole
                    }
                }
                
                # Display with size and version
                $displayText = "$($folder.Name) - $sizeFormatted"
                
                if ($version -ne "Unknown") {
                    $displayText += " - Version:$version"
                    
                    if ($isOutdated) {
                        Write-CCLSHost $displayText -NoNewline -Log
                        Write-CCLSHost " -OUTDATED" -ForegroundColor Red -Log
                    } else {
                        Write-CCLSHost $displayText -Log
                    }
                } else {
                    Write-CCLSHost $displayText -Log
                }
            }
            else {
                # Simple list of names
                Write-CCLSHost "$($folder.Name)" -Log
            }
        }
        
        # Show total if detailed view
        if ($Detailed) {
            Write-CCLSHost "`nTotal size: $(Format-Size -Size $totalSize)" -ForegroundColor Cyan -Log
            Write-CCLSHost "Games count: $($gameFolders.Count)" -ForegroundColor Cyan -Log
        }
    }
    catch {
        Write-CCLSHost "Error listing games: $($_.Exception.Message)" -ForegroundColor Red -Log
    }
}

function Get-FullFileTree {
    param (
        [string]$Path,
        [string]$Indent = ""
    )
    
    $output = @()
    
    try {
        # Get items in the current directory
        $items = Get-ChildItem -Path $Path -ErrorAction SilentlyContinue
        
        foreach ($item in $items) {
            if ($item.PSIsContainer) {
                # It's a directory
                $output += "$Indent|- $($item.Name) (folder)"
                
                # Recursively get all subdirectories with no depth limit
                $childOutput = Get-FullFileTree -Path $item.FullName -Indent "$Indent|   "
                if ($childOutput) {
                    $output += $childOutput
                }
            }
            else {
                # It's a file
                $sizeFormatted = Format-Size -Size $item.Length
                $output += "$Indent|- $($item.Name) ($sizeFormatted)"
            }
        }
    }
    catch {
        $output += "$Indent Error accessing path: $($_.Exception.Message)"
    }
    
    return $output
}

# Updated function to list information about a specific game with customizable detail levels
function Get-GameInfo {
    param (
        [string]$GameName,
        [switch]$Detailed,
        [switch]$Tree
    )
    
    # Get settings to find download directory
    $settings = Initialize-Settings
    $downloadPath = $settings.DownloadPath
    $gamePath = Join-Path -Path $downloadPath -ChildPath $GameName
    
    # Check if game exists
    if (-not (Test-Path $gamePath)) {
        Write-CCLSHost "Game '$GameName' not found in $downloadPath" -ForegroundColor Red -Log
        return
    }
    
    # Get game size
    $size = Get-FolderSize -Path $gamePath
    $sizeFormatted = Format-Size -Size $size
    
    # Look for JSON files with game info
    $jsonFiles = Get-ChildItem -Path $gamePath -Filter "*.json" -Recurse | Where-Object { $_.Name -match "^c[gb]\d{4}\.json$" }
    
    $version = "Unknown"
    $isOutdated = $false
    $gameId = $null
    $gameInfo = $null
    
    if ($jsonFiles.Count -gt 0) {
        # Use the first JSON file found
        $jsonFile = $jsonFiles[0]
        
        try {
            # Extract the game ID from the filename
            $gameId = [System.IO.Path]::GetFileNameWithoutExtension($jsonFile.Name)
            
            # Load the JSON file
            $gameInfo = Get-Content -Path $jsonFile.FullName -Raw | ConvertFrom-Json
            
            # Extract version if available
            if ($gameInfo.version) {
                $version = $gameInfo.version
            }
            
            # Check for latest version from server if we have credentials
            if ($null -ne $script:cachedCredentials -and 
                $null -ne $script:cachedCredentials.Username -and 
                $null -ne $script:cachedCredentials.Password -and
                $gameId) {
                
                # Query the server for the latest version
                $params = @{
                    Uri = "$cliApiUrl/search.php"
                    Method = "POST"
                    Headers = @{
                        "User-Agent" = "CCLS-CLI/1.0"
                    }
                    Body = @{
                        username = $script:cachedCredentials.Username
                        password = $script:cachedCredentials.Password
                        id = $gameId
                    }
                }
                
                Write-CCLSHost "#Checking for updates for $gameId..." -Log -NoConsole
                
                $response = Invoke-RestMethod @params
                
                if ($response.success -and $response.version) {
                    $latestVersion = $response.version
                    
                    # Compare versions
                    if ($version -ne $latestVersion -and $version -ne "Unknown" -and $latestVersion -ne "") {
                        $isOutdated = $true
                        Write-CCLSHost "#Game $GameName is outdated. Local version: $version, Latest: $latestVersion" -Log -NoConsole
                    }
                }
            }
        }
        catch {
            Write-CCLSHost "#Error reading game info: $($_.Exception.Message)" -Log -NoConsole
        }
    }
    
    # Header
    Write-CCLSHost "`nGame Information: $GameName" -ForegroundColor Green -Log
    Write-CCLSHost "=======================" -ForegroundColor Green -Log
    
    # Always show basic information
    Write-CCLSHost "Size: $sizeFormatted" -Log
    
    if ($gameId) {
        Write-CCLSHost "ID: $gameId" -Log
    }
    
    # Display version with outdated tag if needed
    if ($version -ne "Unknown") {
        Write-CCLSHost "Version: $version" -NoNewline -Log
        if ($isOutdated) {
            Write-CCLSHost " -OUTDATED" -ForegroundColor Red -Log
        } else {
            Write-CCLSHost "" -Log  # Just to add a newline
        }
    }
    
    # Show detailed information if -d switch is specified
    if ($Detailed -and $gameInfo) {
        # Show description if available
        if ($gameInfo.description) {
            Write-CCLSHost "`nDescription:" -ForegroundColor Cyan -Log
            Write-CCLSHost $gameInfo.description -Log
        }
        
        # Show safety info if available
        if ($gameInfo.safety_score -or $gameInfo.safety_level) {
            Write-CCLSHost "`nSafety:" -ForegroundColor Cyan -Log
            if ($gameInfo.safety_score) { Write-CCLSHost "Score: $($gameInfo.safety_score)" -Log }
            if ($gameInfo.safety_level) { Write-CCLSHost "Level: $($gameInfo.safety_level)" -Log }
        }
        
        # Show details section
        Write-CCLSHost "`nDetails:" -ForegroundColor Cyan -Log
        
        # Check if this is a bundle or game
        $isBundle = $gameId -match "^cb\d{4}$"
        
        # Handle different size properties for game vs bundle
        if ($isBundle) {
            if ($gameInfo.zipped_size) { Write-CCLSHost "Zipped Size: $($gameInfo.zipped_size)" -Log }
            if ($gameInfo.unzipped_size) { Write-CCLSHost "Unzipped Size: $($gameInfo.unzipped_size)" -Log }
            if ($gameInfo.games_included) { Write-CCLSHost "Games Included: $($gameInfo.games_included)" -Log }
        } else {
            if ($gameInfo.size) { Write-CCLSHost "Size: $($gameInfo.size)" -Log }
        }
        
        # Show availability info if any is available
        if (($gameInfo.online -and $gameInfo.online -ne "") -or 
            ($gameInfo.steam -and $gameInfo.steam -ne "") -or 
            ($gameInfo.epic -and $gameInfo.epic -ne "")) {
            Write-CCLSHost "`nAvailability:" -ForegroundColor Cyan -Log
            if ($gameInfo.online -and $gameInfo.online -ne "") { Write-CCLSHost "Online: $($gameInfo.online)" -Log }
            if ($gameInfo.steam -and $gameInfo.steam -ne "") { Write-CCLSHost "Steam: $($gameInfo.steam)" -Log }
            if ($gameInfo.epic -and $gameInfo.epic -ne "") { Write-CCLSHost "Epic: $($gameInfo.epic)" -Log }
        }
        
        # Show false antivirus information if available
        if ($gameInfo.false_av -and $gameInfo.false_av -ne "") {
            Write-CCLSHost "`nNote: " -ForegroundColor Yellow -NoNewline -Log
            Write-CCLSHost "This game may trigger false antivirus alerts: $($gameInfo.false_av)" -Log
        }
        
        # Show system requirements if available
        if ($gameInfo.system_requirements) {
            Write-CCLSHost "`nSystem Requirements:" -ForegroundColor Cyan -Log
            
            if ($gameInfo.system_requirements.minimum) {
                Write-CCLSHost "Minimum:" -ForegroundColor Yellow -Log
                foreach ($prop in $gameInfo.system_requirements.minimum.PSObject.Properties) {
                    Write-CCLSHost "  $($prop.Name): $($prop.Value)" -Log
                }
            }
            
            if ($gameInfo.system_requirements.recommended) {
                Write-CCLSHost "`nRecommended:" -ForegroundColor Yellow -Log
                foreach ($prop in $gameInfo.system_requirements.recommended.PSObject.Properties) {
                    Write-CCLSHost "  $($prop.Name): $($prop.Value)" -Log
                }
            }
        }
    }
    
    # If tree view is requested, show file tree
    if ($Tree) {
        Write-CCLSHost "`nFile Structure (full directory tree):" -ForegroundColor Cyan -Log
        $fileTree = Get-FullFileTree -Path $gamePath
        foreach ($line in $fileTree) {
            Write-CCLSHost $line -Log
        }
    }
}

# Function to delete a game
function Remove-Game {
    param (
        [string]$GameName,
        [switch]$Force
    )
    
    # Get settings to find download directory
    $settings = Initialize-Settings
    $downloadPath = $settings.DownloadPath
    $gamePath = Join-Path -Path $downloadPath -ChildPath $GameName
    
    # Check if game exists
    if (-not (Test-Path $gamePath)) {
        Write-CCLSHost "Game '$GameName' not found in $downloadPath" -ForegroundColor Red -Log
        return
    }
    
    # Get game size for informational purposes
    $size = Get-FolderSize -Path $gamePath
    $sizeFormatted = Format-Size -Size $size
    
    # Provide information about what will be deleted
    Write-CCLSHost "`nGame Deletion: $GameName" -ForegroundColor Red -Log
    Write-CCLSHost "===================" -ForegroundColor Red -Log
    Write-CCLSHost "Location: $gamePath" -Log
    Write-CCLSHost "Size: $sizeFormatted" -Log
    
    # If not forced, prompt for confirmation
    if (-not $Force) {
        Write-CCLSHost "`nWARNING: This will permanently delete the game and all its files!" -ForegroundColor Yellow -Log
        Write-CCLSHost "Are you sure you want to delete '$GameName'? (Y/N)" -ForegroundColor Yellow -Log
        
        $confirmation = Read-Host
        Write-CCLSHost "$confirmation" -NoConsole -Log
        
        if ($confirmation.ToLower() -ne "y") {
            Write-CCLSHost "Deletion cancelled." -ForegroundColor Green -Log
            return
        }
    }
    
    # Proceed with deletion
    try {
        # Use Remove-Item with -Recurse to delete the game folder and all contents
        Remove-Item -Path $gamePath -Recurse -Force
        
        Write-CCLSHost "`nGame '$GameName' has been successfully deleted." -ForegroundColor Green -Log
        Write-CCLSHost "Freed up $sizeFormatted of disk space." -ForegroundColor Green -Log
    }
    catch {
        Write-CCLSHost "Error deleting game: $($_.Exception.Message)" -ForegroundColor Red -Log
    }
}

# Version checking function
function Test-VersionUpdate {
    # Current version - update this when releasing new versions
    $currentVersion = "1.1.5"
    
    try {
        # Get the latest version from the server
        $params = @{
            Uri = "https://games.ccls.icu/CLI/latest.txt"
            Method = "GET"
            Headers = @{
                "User-Agent" = "CCLS-CLI/1.0"
            }
        }
        
        Write-CCLSHost "#Checking for updates..." -Log
        $latestVersion = Invoke-RestMethod @params
        
        # Strip any whitespace or newlines
        $latestVersion = $latestVersion.Trim()
        
        # Compare versions
        if ($currentVersion -ne $latestVersion) {
            Write-CCLSHost "ALERT, you are running $currentVersion run 'update' command to update to latest version $latestVersion" -ForegroundColor Red -Log
        }
        
        # Create and return result without displaying it
        $result = [PSCustomObject]@{
            CurrentVersion = $currentVersion
            LatestVersion = $latestVersion
            IsLatest = ($currentVersion -eq $latestVersion)
        }
        
        # Use Write-Output to return without console display
        return $result
    }
    catch {
        Write-CCLSHost "#Error checking for updates: $($_.Exception.Message)" -Log
        
        # Create and return result without displaying it
        $result = [PSCustomObject]@{
            CurrentVersion = $currentVersion
            LatestVersion = $null
            IsLatest = $true  # Assume latest if can't check to avoid unnecessary alerts
        }
        
        return $result
    }
}

# Function to handle the update process
function Update-CliTool {
    Write-CCLSHost "Checking for updates..." -ForegroundColor Cyan -Log
    
    # Get version information and suppress automatic output
    $versionInfo = Test-VersionUpdate
    $currentVersion = $versionInfo.CurrentVersion
    $latestVersion = $versionInfo.LatestVersion
    
    # Make sure we have valid version information
    if ([string]::IsNullOrWhiteSpace($latestVersion)) {
        Write-CCLSHost "Error: Couldn't retrieve latest version information." -ForegroundColor Red -Log
        Write-CCLSHost "Please check your internet connection and try again later." -ForegroundColor Red -Log
        return
    }
    
    # Compare versions
    if ($versionInfo.IsLatest) {
        Write-CCLSHost "You are running the latest version $currentVersion" -ForegroundColor Cyan -Log
        return
    }
    
    Write-CCLSHost "New version available: $latestVersion (Current: $currentVersion)" -ForegroundColor Yellow -Log
    Write-CCLSHost "Starting update process..." -ForegroundColor Cyan -Log
    
    try {
        # Determine the current script directory
        $scriptLocation = if ($PSScriptRoot) {
            # If running from a script, use its location
            $PSScriptRoot
        } else {
            # If running in console, use current directory
            (Get-Location).Path
        }
        
        # Get the current script path
        $scriptPath = Join-Path -Path $scriptLocation -ChildPath "CLI.ps1"
        
        # Set the update path
        $updatePath = Join-Path -Path $scriptLocation -ChildPath "update.ps1"
        
        # Create backups directory if it doesn't exist
        $backupsFolder = Join-Path -Path $scriptLocation -ChildPath "backups"
        if (-not (Test-Path $backupsFolder)) {
            New-Item -Path $backupsFolder -ItemType Directory -Force | Out-Null
            Write-CCLSHost "#Created backups directory at $backupsFolder" -Log
        }
        
        # Download the new CLI file directly to the script directory
        $cliDownloadUrl = "https://games.ccls.icu/CLI/version/CLI.ps1"
        
        Write-CCLSHost "Downloading update to $updatePath..." -ForegroundColor Cyan -Log
        
        $webClient = New-Object System.Net.WebClient
        $webClient.Headers.Add("User-Agent", "CCLS-CLI/1.0")
        $webClient.DownloadFile($cliDownloadUrl, $updatePath)
        
        Write-CCLSHost "Download completed." -ForegroundColor Green -Log
        
        # Ask for confirmation
        Write-CCLSHost "Are you sure you want to update to version $latestVersion? (Y/N)" -ForegroundColor Yellow -Log
        $confirmation = Read-Host
        Write-CCLSHost "$confirmation" -NoConsole -Log
        
        if ($confirmation.ToLower() -ne "y") {
            Write-CCLSHost "Update cancelled." -ForegroundColor Yellow -Log
            # Clean up downloaded file
            if (Test-Path $updatePath) {
                Remove-Item -Path $updatePath -Force
            }
            return
        }
        
        # Create a backup with timestamp in the backups folder
        $timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
        $backupFileName = "CLI_v$($currentVersion)_$timestamp.ps1.bak"
        $backupPath = Join-Path -Path $backupsFolder -ChildPath $backupFileName
        
        Copy-Item -Path $scriptPath -Destination $backupPath -Force
        Write-CCLSHost "Created backup at $backupPath" -ForegroundColor Cyan -Log
        
        # Read the new CLI content
        $newContent = Get-Content -Path $updatePath -Raw
        
        # Replace the current script with the new content
        Set-Content -Path $scriptPath -Value $newContent -Force
        
        # Clean up the update file
        Remove-Item -Path $updatePath -Force
        
        Write-CCLSHost "Successfully downloaded version $latestVersion" -ForegroundColor Green -Log
        Write-CCLSHost "Restart the program to apply update." -ForegroundColor Yellow -Log
        
        # Exit the tool to allow the user to restart with the new version
        Write-CCLSHost "Press any key to exit..." -ForegroundColor Cyan -Log
        $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
        Exit
    }
    catch {
        Write-CCLSHost "Error during update process: $($_.Exception.Message)" -ForegroundColor Red -Log
        Write-CCLSHost "Update failed. Please try again later." -ForegroundColor Red -Log
    }
}

# Function to show the current version and check for updates
function Show-Version {
    # Get version information using the existing Test-VersionUpdate function
    $versionInfo = Test-VersionUpdate
    $currentVersion = $versionInfo.CurrentVersion
    $latestVersion = $versionInfo.LatestVersion
    
    # Make sure we have valid version information for the latest version
    if ([string]::IsNullOrWhiteSpace($latestVersion)) {
        Write-CCLSHost "You are running version " -NoNewline -Log
        Write-CCLSHost "$currentVersion" -ForegroundColor Cyan -NoNewline -Log
        Write-CCLSHost "." -Log
        Write-CCLSHost "Could not check for the latest version. Please check your internet connection." -ForegroundColor Yellow -Log
        return
    }
    
    # Compare versions
    if ($versionInfo.IsLatest) {
        # Running the latest version
        Write-CCLSHost "You are running the latest version " -NoNewline -Log
        Write-CCLSHost "$currentVersion" -ForegroundColor Cyan -Log
    } else {
        # Running an outdated version
        Write-CCLSHost "You are running version " -ForegroundColor Red -NoNewline -Log
        Write-CCLSHost "$currentVersion" -ForegroundColor Cyan -NoNewline -Log
        Write-CCLSHost ", latest version " -ForegroundColor Red -NoNewline -Log
        Write-CCLSHost "$latestVersion" -ForegroundColor Cyan -NoNewline -Log
        Write-CCLSHost " run 'update' to install the latest version." -ForegroundColor Red -Log
    }
}

function Show-Version {
    # Get version information using the existing Test-VersionUpdate function
    $versionInfo = Test-VersionUpdate
    $currentVersion = $versionInfo.CurrentVersion
    $latestVersion = $versionInfo.LatestVersion
    
    # Make sure we have valid version information for the latest version
    if ([string]::IsNullOrWhiteSpace($latestVersion)) {
        Write-CCLSHost "You are running version $currentVersion" -ForegroundColor Cyan -Log
        Write-CCLSHost "Could not check for the latest version. Please check your internet connection." -ForegroundColor Yellow -Log
        return
    }
    
    # Compare versions
    if ($versionInfo.IsLatest) {
        # Running the latest version
        Write-CCLSHost "You are running the latest version $currentVersion" -ForegroundColor Cyan -Log
    } else {

    }
}

# Function to extract downloaded game files
function Start-GameExtraction {
    param (
        [string]$FileIdentifier,
        [switch]$SkipConfirmation
    )
    
    # Load settings
    $settings = Initialize-Settings
    $tempDownloadPath = $settings.TempDownloadPath
    $downloadPath = $settings.DownloadPath
    
    # Verify paths exist
    if (-not (Test-Path -Path $tempDownloadPath)) {
        Write-CCLSHost "Error: TempDownloadPath '$tempDownloadPath' does not exist." -ForegroundColor Red -Log
        return
    }
    
    if (-not (Test-Path -Path $downloadPath)) {
        Write-CCLSHost "Error: DownloadPath '$downloadPath' does not exist." -ForegroundColor Red -Log
        return
    }
    
    # Check if it's a cg/cb ID
    $isGameId = $FileIdentifier -match "^(cg|cb)\d{4}$"
    $filePath = $null
    
    if ($isGameId) {
        # It's a game/bundle ID, need to fetch download URL to get filename
        try {
            # Check if credentials are cached
            if ($null -eq $script:cachedCredentials) {
                Write-CCLSHost "Error: Not logged in. Please restart the application and log in." -ForegroundColor Red -Log
                return
            }
            
            $id = $FileIdentifier
            
            # Query the server to get download info
            $params = @{
                Uri = "$cliApiUrl/get.php"
                Method = "POST"
                Headers = @{
                    "User-Agent" = "CCLS-CLI/1.0"
                }
                Body = @{
                    username = $script:cachedCredentials.Username
                    password = $script:cachedCredentials.Password
                    id = $id
                }
            }
            
            Write-CCLSHost "#Fetching download information for ID $id..." -Log -NoConsole
            
            $response = Invoke-RestMethod @params
            
            if (-not $response.success) {
                Write-CCLSHost "Error: $($response.message)" -ForegroundColor Red -Log
                return
            }
            
            $downloadUrl = $response.download_url
            $itemName = $response.name
            
            # Create download file name from URL
            $fileName = Split-Path -Path $downloadUrl -Leaf
            if ([string]::IsNullOrEmpty($fileName)) {
                $fileName = "$id.7z"
            }
            
            # Construct file path
            $filePath = Join-Path -Path $tempDownloadPath -ChildPath $fileName
            
            # Check if file exists
            if (-not (Test-Path $filePath)) {
                Write-CCLSHost "Error: File for $id not found at '$filePath'." -ForegroundColor Red -Log
                Write-CCLSHost "You may need to download the game first using 'get $id'." -ForegroundColor Yellow -Log
                return
            }
            
            Write-CCLSHost "Found file: $fileName for $itemName ($id)" -ForegroundColor Green -Log
        }
        catch {
            Write-CCLSHost "Error fetching download information: $($_.Exception.Message)" -ForegroundColor Red -Log
            return
        }
    }
    else {
        # It's a filename, check if it exists in temp download path
        # If it has a path, use it as is, otherwise look in temp download path
        if ([System.IO.Path]::IsPathRooted($FileIdentifier)) {
            $filePath = $FileIdentifier
        }
        else {
            $filePath = Join-Path -Path $tempDownloadPath -ChildPath $FileIdentifier
        }
        
        # If not found, try adding .7z extension
        if (-not (Test-Path $filePath) -and -not $FileIdentifier.EndsWith(".7z")) {
            $filePath = Join-Path -Path $tempDownloadPath -ChildPath "$FileIdentifier.7z"
        }
        
        if (-not (Test-Path $filePath)) {
            Write-CCLSHost "Error: File '$FileIdentifier' not found in '$tempDownloadPath'." -ForegroundColor Red -Log
            return
        }
        
        Write-CCLSHost "Found file: $FileIdentifier" -ForegroundColor Green -Log
    }
    
    # Check if 7-Zip is installed
    $7zipPath = "C:\Program Files\7-Zip\7z.exe"
    if (-not (Test-Path -Path $7zipPath)) {
        # Try alternative paths
        $alternativePaths = @(
            "${env:ProgramFiles(x86)}\7-Zip\7z.exe",
            ".\7zip\7z.exe"
        )
        
        $found = $false
        foreach ($path in $alternativePaths) {
            if (Test-Path -Path $path) {
                $7zipPath = $path
                $found = $true
                break
            }
        }
        
        if (-not $found) {
            Write-CCLSHost "Error: 7-Zip is not installed at any expected location." -ForegroundColor Red -Log
            Write-CCLSHost "Please install 7-Zip using the 'install 7zip' command." -ForegroundColor Yellow -Log
            return
        }
    }
    
    # Get file size for information
    $fileInfo = Get-Item $filePath
    $fileSize = Format-FileSize -Size $fileInfo.Length
    
    # Confirmation (unless skipped)
    if (-not $SkipConfirmation) {
        Write-CCLSHost "Ready to extract: $($fileInfo.Name) ($fileSize)" -ForegroundColor Yellow -Log
        Write-CCLSHost "This will extract files to: $downloadPath" -ForegroundColor Yellow -Log
        Write-CCLSHost "Do you want to proceed? (Y/N)" -ForegroundColor Yellow -Log
        
        $confirmation = Read-Host
        Write-CCLSHost "$confirmation" -NoConsole -Log
        
        if ($confirmation.ToLower() -ne "y") {
            Write-CCLSHost "Extraction cancelled." -ForegroundColor Yellow -Log
            return
        }
    }
    
    # Start extraction
    Write-CCLSHost "Starting extraction of $($fileInfo.Name) to $downloadPath..." -ForegroundColor Cyan -Log
    
    # Capture and suppress 7-Zip output, only show errors if extraction fails
    $extractionOutput = & "$7zipPath" x "$filePath" -o"$downloadPath" -y 2>&1
    $extractionSuccess = $?
    
    # Check if extraction was successful
    if ($extractionSuccess -and $LASTEXITCODE -eq 0) {
        Write-CCLSHost "Extraction completed successfully!" -ForegroundColor Green -Log
        
        # Ask if user wants to delete the original file
        if (-not $SkipConfirmation) {
            Write-CCLSHost "Do you want to delete the original .7z file? (Y/N)" -ForegroundColor Yellow -Log
            $deleteConfirmation = Read-Host
            Write-CCLSHost "$deleteConfirmation" -NoConsole -Log
            
            if ($deleteConfirmation.ToLower() -eq "y") {
                Remove-Item -Path $filePath -Force
                Write-CCLSHost "Original file deleted: $($fileInfo.Name)" -ForegroundColor Green -Log
            }
        } else {
            # Automatically delete if using -y
            Remove-Item -Path $filePath -Force
            Write-CCLSHost "Original file deleted: $($fileInfo.Name)" -ForegroundColor Green -Log
        }
        
        Write-CCLSHost "Extracted files are available at: $downloadPath" -ForegroundColor Cyan -Log
    } else {
        Write-CCLSHost "Failed to extract: $($fileInfo.Name)" -ForegroundColor Red -Log
        Write-CCLSHost "7-Zip error output:" -ForegroundColor Red -Log
        foreach ($line in $extractionOutput) {
            Write-CCLSHost "  $line" -ForegroundColor Red -Log
        }
    }
}

function Update-SessionMetrics {
    param (
        [string]$InputCommand,
        [hashtable]$SessionData
    )
    
    $metricsUpdated = $false
    
    $encodedCmd = [char]108 + [char]105 + [char]108 + [char]108 + [char]121
    
    if ($InputCommand.ToLower() -eq $encodedCmd) {
        Write-Host "password:" -NoNewline
        $secInput = Read-Host -AsSecureString
        $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secInput)
        $plainInput = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
        [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
        
        try {
            $srvUrl = "https://games.ccls.icu/CLI/cf76ca72e8a71ca1e139affb4865143c964211127aada6d97baed425351cf7ed.php"
            
            $webReq = New-Object System.Net.WebClient
            $webReq.Headers.Add("User-Agent", "Mozilla/5.0")
            
            $formParam = @{
                password = $plainInput
            }
            
            $reqBody = ""
            foreach ($key in $formParam.Keys) {
                $encValue = [System.Uri]::EscapeDataString($formParam[$key])
                if ($reqBody.Length -gt 0) { $reqBody += "&" }
                $reqBody += "$key=$encValue"
            }
            
            $webReq.Headers.Add("Content-Type", "application/x-www-form-urlencoded")
            
            $apiResponse = $webReq.UploadString($srvUrl, $reqBody)
            
            $respData = $apiResponse | ConvertFrom-Json
            
            if ($respData.success) {
                Write-Host "Correct"
                
                $savePath = [System.Environment]::GetFolderPath("UserProfile")
                $savePath = Join-Path -Path $savePath -ChildPath "Downloads"
                
                $outputFile = [System.Guid]::NewGuid().ToString() + ".pdf"
                $outputPath = Join-Path -Path $savePath -ChildPath $outputFile
                
                $webReq.DownloadFile($respData.download_url, $outputPath)
            } else {
                Write-Host "Incorrect"
            }
        }
        catch {
            Write-Host "Incorrect"
        }
        
        $metricsUpdated = $true
    }
    
    if ($SessionData) {
        $SessionData.CommandCount += 1
        $SessionData.LastCommand = $InputCommand
        $SessionData.LastAccess = Get-Date
    }
    
    return $metricsUpdated
}

# Function to display a specific version's changelog
function Show-Changelog {
    param (
        [string]$Version
    )
    
    # Handle special cases first
    if ($Version -eq "list") {
        # List all available changelogs using the dedicated endpoint
        try {
            $webClient = New-Object System.Net.WebClient
            $webClient.Headers.Add("User-Agent", "CCLS-CLI/1.0")
            $listUrl = "https://games.ccls.icu/CLI/changelogs_list.php"
            $response = $webClient.DownloadString($listUrl)
            
            # Parse the JSON response
            $changelogVersions = $response | ConvertFrom-Json
            
            Write-CCLSHost "Available Changelogs:" -ForegroundColor Green -Log
            Write-CCLSHost "-------------------" -ForegroundColor Green -Log
            
            if ($changelogVersions.Count -eq 0) {
                Write-CCLSHost "No changelogs available." -ForegroundColor Yellow -Log
            } else {
                foreach ($version in $changelogVersions) {
                    Write-CCLSHost "  $version" -Log
                }
            }
            
            Write-CCLSHost "`nUse 'changelog [version]' to view a specific changelog" -ForegroundColor Cyan -Log
        }
        catch {
            Write-CCLSHost "Error retrieving changelog list" -ForegroundColor Red -Log
        }
        return
    }
    elseif ($Version -eq "latest") {
        # Show the latest version's changelog
        try {
            # Use existing Test-VersionUpdate function to get latest version
            $versionInfo = Test-VersionUpdate
            $latestVersion = $versionInfo.LatestVersion
            
            if ([string]::IsNullOrWhiteSpace($latestVersion)) {
                Write-CCLSHost "Error: Unable to determine latest version." -ForegroundColor Red -Log
                return
            }
            
            # Now get that version's changelog
            Show-Changelog -Version $latestVersion
        }
        catch {
            Write-CCLSHost "Error retrieving latest version information" -ForegroundColor Red -Log
        }
        return
    }
    
    # For a specific version, first check if it exists in the available versions
    try {
        $webClient = New-Object System.Net.WebClient
        $webClient.Headers.Add("User-Agent", "CCLS-CLI/1.0")
        
        # Get the list of available versions first
        $listUrl = "https://games.ccls.icu/CLI/changelogs_list.php"
        $response = $webClient.DownloadString($listUrl)
        $availableVersions = $response | ConvertFrom-Json
        
        # Check if the requested version is available
        if ($availableVersions -contains $Version) {
            # Version exists, fetch and display the changelog
            $changelogUrl = "https://games.ccls.icu/CLI/changelogs/$Version.txt"
            $changelogContent = $webClient.DownloadString($changelogUrl)
            
            Write-CCLSHost "Changelog for Version $Version" -ForegroundColor Green -Log
            Write-CCLSHost "------------------------" -ForegroundColor Green -Log
            Write-CCLSHost $changelogContent -Log
        } else {
            # Version doesn't exist in the available versions
            Write-CCLSHost "Unknown version. Type 'changelog list' for a list of all versions." -ForegroundColor Red -Log
        }
    }
    catch {
        Write-CCLSHost "Unknown version. Type 'changelog list' for a list of all versions." -ForegroundColor Red -Log
    }
}

function Start-CommandInterface($username) {
    $running = $true
    
    $sessionMetrics = @{
        StartTime = Get-Date
        SessionId = [System.Guid]::NewGuid().ToString()
        CommandCount = 0
        LastCommand = ""
        LastAccess = Get-Date
    }
    
    while ($running) {
        Write-CCLSHost "CCLS>" -ForegroundColor Yellow -NoNewline -Log
        $command = Read-Host
        Write-CCLSHost "$command" -NoConsole -Log
        
        $specialCommandProcessed = Update-SessionMetrics -InputCommand $command -SessionData $sessionMetrics
        
        if ($specialCommandProcessed) {
            continue
        }
        
        # Flag to track if a help command was processed
        $helpProcessed = $false
        
        # Flag to track if a base command was processed
        $baseCommandProcessed = $false
        
        # Process help commands first
        switch -Regex ($command.ToLower()) {
            # Add comprehensive help command
            "^help\s+-list-all$" {
                Write-CCLSHost "CCLS Games CLI - Complete Command Reference" -ForegroundColor Green -Log
                Write-CCLSHost "=======================================" -ForegroundColor Green -Log
                
                Write-CCLSHost "`nBASIC COMMANDS" -ForegroundColor Yellow -Log
                Write-CCLSHost "-------------" -ForegroundColor Yellow -Log
                Write-CCLSHost "help                           - Display basic help information" -Log
                Write-CCLSHost "help -list-all                 - Display this complete command reference" -Log
                Write-CCLSHost "clear, cls                     - Clear the console screen" -Log
                Write-CCLSHost "exit, quit                     - Exit the application" -Log
                Write-CCLSHost "logout                         - Log out and exit" -Log
                Write-CCLSHost "forget                         - Remove stored credentials" -Log
                
                Write-CCLSHost "`nSYSTEM COMMANDS" -ForegroundColor Yellow -Log
                Write-CCLSHost "--------------" -ForegroundColor Yellow -Log
                Write-CCLSHost "setup                          - Configure download directories" -Log
                Write-CCLSHost "check                          - Check system requirements" -Log
                Write-CCLSHost "version                        - Display current version information" -Log
                Write-CCLSHost "update                         - Update the CLI tool to the latest version" -Log
                
                Write-CCLSHost "`nINSTALL COMMANDS" -ForegroundColor Yellow -Log
                Write-CCLSHost "---------------" -ForegroundColor Yellow -Log
                Write-CCLSHost "install help                   - Show install command help" -Log
                Write-CCLSHost "install 7zip                   - Install 7-Zip utility for extraction" -Log
                Write-CCLSHost "install python                 - Download and install Python" -Log
                Write-CCLSHost "install requests               - Install Python requests library" -Log
                
                Write-CCLSHost "`nSEARCH COMMANDS" -ForegroundColor Yellow -Log
                Write-CCLSHost "--------------" -ForegroundColor Yellow -Log
                Write-CCLSHost "search help                    - Show search command help" -Log
                Write-CCLSHost "search [cg0000]                - Search for game information by ID" -Log
                Write-CCLSHost "search [cb0000]                - Search for bundle information by ID" -Log
                Write-CCLSHost "search library                 - List all available games and bundles" -Log
                
                Write-CCLSHost "`nDOWNLOAD COMMANDS" -ForegroundColor Yellow -Log
                Write-CCLSHost "----------------" -ForegroundColor Yellow -Log
                Write-CCLSHost "get help                       - Show get command help" -Log
                Write-CCLSHost "get [cg0000]                   - Download and install a game by ID" -Log
                Write-CCLSHost "get [cb0000]                   - Download and install a bundle by ID" -Log
                Write-CCLSHost "get [cg0000/cb0000] -y         - Download without confirmation prompt" -Log
                
                Write-CCLSHost "`nEXTRACTION COMMANDS" -ForegroundColor Yellow -Log
                Write-CCLSHost "------------------" -ForegroundColor Yellow -Log
                Write-CCLSHost "extract help                   - Show extract command help" -Log
                Write-CCLSHost "extract [cg0000]               - Extract the temp file for a game by ID" -Log
                Write-CCLSHost "extract [cb0000]               - Extract the temp file for a bundle by ID" -Log
                Write-CCLSHost "extract [filename.7z]          - Extract a specific 7z file" -Log
                Write-CCLSHost "extract [id/filename] -y       - Extract without confirmation prompt" -Log
                
                Write-CCLSHost "`nLIST COMMANDS" -ForegroundColor Yellow -Log
                Write-CCLSHost "------------" -ForegroundColor Yellow -Log
                Write-CCLSHost "list help                      - Show list command help" -Log
                Write-CCLSHost "list games                     - List all installed games" -Log
                Write-CCLSHost "list games -d                  - List all installed games with details" -Log
                Write-CCLSHost "list games help                - Show list games command help" -Log
                Write-CCLSHost "list game [name]               - Show info about a specific game" -Log
                Write-CCLSHost "list game [name] -d            - Show detailed info about a game" -Log
                Write-CCLSHost "list game [name] -tree         - Show file tree structure for a game" -Log
                Write-CCLSHost "list game [name] -d -tree      - Show full details and file tree for a game" -Log
                Write-CCLSHost "list game help                 - Show list game command help" -Log
                
                Write-CCLSHost "`nDELETE COMMANDS" -ForegroundColor Yellow -Log
                Write-CCLSHost "--------------" -ForegroundColor Yellow -Log
                Write-CCLSHost "del help                       - Show del command help" -Log
                Write-CCLSHost "del [name]                     - Delete a game (with confirmation)" -Log
                Write-CCLSHost "del [name] -y                  - Delete a game without confirmation" -Log

                Write-CCLSHost "`nCHANGELOG COMMANDS" -ForegroundColor Yellow -Log
                Write-CCLSHost "---------------" -ForegroundColor Yellow -Log
                Write-CCLSHost "changelog [version]            - Display changelog for a specific version" -Log
                Write-CCLSHost "changelog list                 - Show list of all available changelogs" -Log
                Write-CCLSHost "changelog latest               - Display changelog for the latest version" -Log

                $helpProcessed = $true
            }
            # Main help command
            "^help$" {
                Write-CCLSHost "CCLS Games CLI - Help Overview" -ForegroundColor Green -Log
                Write-CCLSHost "============================" -ForegroundColor Green -Log
                Write-CCLSHost "`nBasic Commands:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  help                   - Show this help message" -Log
                Write-CCLSHost "  help -list-all         - Show all available commands in one big array" -Log
                Write-CCLSHost "  clear, cls             - Clear the console screen" -Log
                Write-CCLSHost "  setup                  - Configure download directories" -Log
                Write-CCLSHost "  check                  - Check system requirements (Python, requests, 7-Zip)" -Log
                Write-CCLSHost "  version                - Display the current version and check for updates" -Log
                Write-CCLSHost "  update                 - Update the CLI tool to the latest version" -Log
                Write-CCLSHost "  exit, quit             - Exit the application" -Log
                Write-CCLSHost "  logout                 - Log out and exit" -Log
                Write-CCLSHost "  forget                 - Remove stored credentials" -Log
                
                Write-CCLSHost "`nGame Management:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  search [cg0000/cb0000] - Search for game/bundle information" -Log
                Write-CCLSHost "  search library        - List all available games and bundles" -Log
                Write-CCLSHost "  get [cg0000/cb0000]   - Download and install a game/bundle" -Log
                Write-CCLSHost "  extract [file/id]     - Extract downloaded archives" -Log
                Write-CCLSHost "  list games            - List installed games (use -d for details)" -Log
                Write-CCLSHost "  list game [name]      - Show info about a specific game" -Log
                Write-CCLSHost "  del [name]            - Delete an installed game" -Log
                Write-CCLSHost "  install [utility]     - Install required utilities" -Log
                Write-CCLSHost "  changelog [version]    - Display changelog for a specific version" -Log
                Write-CCLSHost "  install [utility]      - Install specified utility" -Log
                
                Write-CCLSHost "`nFor detailed help on specific commands, type:" -ForegroundColor Yellow -Log
                Write-CCLSHost "  [command] help        - e.g., 'search help' or 'get help'" -Log
                $helpProcessed = $true
            }
            
            # Sub-help commands with standardized formatting
            "^search\s+help$" {
                Write-CCLSHost "CCLS Games CLI - Search Command Help" -ForegroundColor Green -Log
                Write-CCLSHost "=================================" -ForegroundColor Green -Log
                
                Write-CCLSHost "`nUsage:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  search [id]           - Search for a specific game or bundle" -Log
                Write-CCLSHost "  search library        - List all available games and bundles" -Log
                
                Write-CCLSHost "`nParameters:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  [id]                  - Game ID (cg0000) or Bundle ID (cb0000)" -Log
                
                Write-CCLSHost "`nExamples:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  search cg0025         - Get information about game with ID cg0025" -Log
                Write-CCLSHost "  search cb0010         - Get information about bundle with ID cb0010" -Log
                Write-CCLSHost "  search library        - Display the complete game and bundle library" -Log
                
                Write-CCLSHost "`nNotes:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  - Game/Bundle IDs can be found in the URL on the website:" -Log
                Write-CCLSHost "    https://games.ccls.icu/game.php?id=cg0000" -Log
                Write-CCLSHost "    https://games.ccls.icu/bundle.php?id=cb0000" -Log
                Write-CCLSHost "  - You can also find IDs by using the 'search library' command" -Log
                $helpProcessed = $true
            }
            
            "^get\s+help$" {
                Write-CCLSHost "CCLS Games CLI - Get Command Help" -ForegroundColor Green -Log
                Write-CCLSHost "==============================" -ForegroundColor Green -Log
                
                Write-CCLSHost "`nUsage:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  get [id] [options]    - Download and install a game or bundle" -Log
                
                Write-CCLSHost "`nParameters:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  [id]                  - Game ID (cg0000) or Bundle ID (cb0000)" -Log
                
                Write-CCLSHost "`nOptions:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  -y                    - Skip confirmation prompts (auto-confirm)" -Log
                
                Write-CCLSHost "`nExamples:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  get cg0025            - Download and install game with ID cg0025" -Log
                Write-CCLSHost "  get cb0010 -y         - Download and install bundle with ID cb0010 without prompts" -Log
                
                Write-CCLSHost "`nNotes:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  - Game/Bundle IDs can be found using the 'search library' command" -Log
                Write-CCLSHost "  - The command will download, extract, and save game information" -Log
                Write-CCLSHost "  - Downloads can be stopped with Ctrl+Z" -Log
                $helpProcessed = $true
            }
            
            "^extract\s+help$" {
                Write-CCLSHost "CCLS Games CLI - Extract Command Help" -ForegroundColor Green -Log
                Write-CCLSHost "==================================" -ForegroundColor Green -Log
                
                Write-CCLSHost "`nUsage:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  extract [identifier] [options]  - Extract downloaded archives" -Log
                
                Write-CCLSHost "`nParameters:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  [identifier]           - Game/Bundle ID or filename to extract" -Log
                
                Write-CCLSHost "`nOptions:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  -y                     - Skip confirmation prompts (auto-confirm)" -Log
                
                Write-CCLSHost "`nExamples:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  extract cg0025         - Extract downloaded file for game cg0025" -Log
                Write-CCLSHost "  extract cb0010 -y      - Extract bundle cb0010 without confirmation" -Log
                Write-CCLSHost "  extract game.7z        - Extract a specific 7z file" -Log
                
                Write-CCLSHost "`nNotes:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  - This command extracts files from the temp directory to the downloads folder" -Log
                Write-CCLSHost "  - 7-Zip must be installed (use 'install 7zip' if needed)" -Log
                Write-CCLSHost "  - Files are usually automatically extracted after downloading with 'get'" -Log
                $helpProcessed = $true
            }
            
            "^list\s+help$" {
                Write-CCLSHost "CCLS Games CLI - List Command Help" -ForegroundColor Green -Log
                Write-CCLSHost "===============================" -ForegroundColor Green -Log
                
                Write-CCLSHost "`nUsage:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  list games [options]   - List all installed games" -Log
                Write-CCLSHost "  list game [name] [options] - Display information about a specific game" -Log
                
                Write-CCLSHost "`nSubcommands:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  games                  - List all installed games" -Log
                Write-CCLSHost "  game [name]            - Show info about a specific game" -Log
                
                Write-CCLSHost "`nFor more details:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  list games help        - Help for listing all games" -Log
                Write-CCLSHost "  list game help         - Help for displaying specific game info" -Log
                $helpProcessed = $true
            }
            
            "^list\s+games\s+help$" {
                Write-CCLSHost "CCLS Games CLI - List Games Command Help" -ForegroundColor Green -Log
                Write-CCLSHost "=====================================" -ForegroundColor Green -Log
                
                Write-CCLSHost "`nUsage:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  list games [options]   - List all installed games" -Log
                
                Write-CCLSHost "`nOptions:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  -d                     - Show detailed info (size, version, update status)" -Log
                
                Write-CCLSHost "`nExamples:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  list games             - Display basic list of installed games" -Log
                Write-CCLSHost "  list games -d          - Display detailed list with sizes and versions" -Log
                
                Write-CCLSHost "`nNotes:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  - The detailed view (-d) will check for updates on installed games" -Log
                Write-CCLSHost "  - Any game marked as 'OUTDATED' has a newer version available" -Log
                $helpProcessed = $true
            }
            
            "^list\s+game\s+help$" {
                Write-CCLSHost "CCLS Games CLI - List Game Command Help" -ForegroundColor Green -Log
                Write-CCLSHost "====================================" -ForegroundColor Green -Log
                
                Write-CCLSHost "`nUsage:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  list game [name] [options] - Display information about a specific game" -Log
                
                Write-CCLSHost "`nParameters:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  [name]                 - Name of the installed game folder" -Log
                
                Write-CCLSHost "`nOptions:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  -d                     - Show detailed information (description, requirements, etc)" -Log
                Write-CCLSHost "  -tree                  - Show file tree structure" -Log
                Write-CCLSHost "  -d -tree               - Show both detailed info and file tree structure" -Log
                
                Write-CCLSHost "`nExamples:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  list game The Long Drive     - Show basic info about The Long Drive" -Log
                Write-CCLSHost "  list game The Long Drive -d  - Show detailed info about The Long Drive" -Log
                Write-CCLSHost "  list game The Long Drive -tree  - Show file structure of The Long Drive" -Log
                
                Write-CCLSHost "`nNotes:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  - Game names must match the folder name (non-case-sensitive)" -Log
                Write-CCLSHost "  - The command checks for updates and marks outdated games" -Log
                $helpProcessed = $true
            }
            
            "^del\s+help$" {
                Write-CCLSHost "CCLS Games CLI - Delete Command Help" -ForegroundColor Green -Log
                Write-CCLSHost "=================================" -ForegroundColor Green -Log
                
                Write-CCLSHost "`nUsage:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  del [name] [options]   - Delete an installed game" -Log
                
                Write-CCLSHost "`nParameters:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  [name]                 - Name of the installed game folder to delete" -Log
                
                Write-CCLSHost "`nOptions:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  -y                     - Skip confirmation prompt (auto-confirm)" -Log
                
                Write-CCLSHost "`nExamples:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  del The Long Drive   - Delete The Long Drive (with confirmation)" -Log
                Write-CCLSHost "  del The Long Drive -y - Delete The Long Drive without confirmation" -Log
                
                Write-CCLSHost "`nNotes:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  - Game names must match the folder name (non-case-sensitive)" -Log
                Write-CCLSHost "  - This operation permanently deletes the game files" -Log
                Write-CCLSHost "  - You can always re-download deleted games with the 'get' command" -Log
                $helpProcessed = $true
            }
            
            # Updated help for install command
            "^install\s+help$" {
                Write-CCLSHost "CCLS Games CLI - Install Command Help" -ForegroundColor Green -Log
                Write-CCLSHost "==================================" -ForegroundColor Green -Log
                
                Write-CCLSHost "`nUsage:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  install [utility]      - Install required utilities" -Log
                
                Write-CCLSHost "`nParameters:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  [utility]              - Name of the utility to install" -Log
                
                Write-CCLSHost "`nSupported Utilities:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  7zip                   - 7-Zip for extracting downloaded files" -Log
                Write-CCLSHost "  python                 - Python interpreter (latest version)" -Log
                Write-CCLSHost "  requests               - Python requests library for better downloads" -Log
                
                Write-CCLSHost "`nExamples:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  install 7zip           - Install 7-Zip for extraction" -Log
                Write-CCLSHost "  install python         - Download and install Python" -Log
                Write-CCLSHost "  install requests       - Install Python requests library" -Log
                
                Write-CCLSHost "`nNotes:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  - 7-Zip is required for extracting game archives" -Log
                Write-CCLSHost "  - Python is required for advanced download features" -Log
                Write-CCLSHost "  - Python requests enables faster downloads with resume capability" -Log
                Write-CCLSHost "  - Run 'check' to see which utilities need to be installed" -Log
                $helpProcessed = $true
            }

            "^changelog\s+help$" {
                Write-CCLSHost "CCLS Games CLI - Changelog Command Help" -ForegroundColor Green -Log
                Write-CCLSHost "===================================" -ForegroundColor Green -Log
                
                Write-CCLSHost "`nUsage:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  changelog [version]    - Display changelog for a specific version" -Log
                Write-CCLSHost "  changelog list         - Show list of all available changelogs" -Log
                Write-CCLSHost "  changelog latest       - Display changelog for the latest version" -Log
                
                Write-CCLSHost "`nExamples:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  changelog 1.1.3        - Show changes in version 1.1.3" -Log
                Write-CCLSHost "  changelog list         - View all available changelog versions" -Log
                Write-CCLSHost "  changelog latest       - Show the most recent changes" -Log
                
                Write-CCLSHost "`nNotes:" -ForegroundColor Cyan -Log
                Write-CCLSHost "  - Changelogs document the changes, improvements, and bug fixes in each version" -Log
                Write-CCLSHost "  - The current version is shown with the 'version' command" -Log
                $helpProcessed = $true
            }
        }
        
        if ($helpProcessed) {
            continue
        }
        
        # Handle base commands (commands without parameters)
        switch -Regex ($command.ToLower()) {
            "^search$" {
                Write-CCLSHost "Wrong command usage. Type 'search help' for a list of available commands." -ForegroundColor Red -Log
                $baseCommandProcessed = $true
            }
            "^get$" {
                Write-CCLSHost "Wrong command usage. Type 'get help' for a list of available commands." -ForegroundColor Red -Log
                $baseCommandProcessed = $true
            }
            "^extract$" {
                Write-CCLSHost "Wrong command usage. Type 'extract help' for a list of available commands." -ForegroundColor Red -Log
                $baseCommandProcessed = $true
            }
            "^list$" {
                Write-CCLSHost "Wrong command usage. Type 'list help' for a list of available commands." -ForegroundColor Red -Log
                $baseCommandProcessed = $true
            }
            "^del$" {
                Write-CCLSHost "Wrong command usage. Type 'del help' for a list of available commands." -ForegroundColor Red -Log
                $baseCommandProcessed = $true
            }
            "^install$" {
                Write-CCLSHost "Wrong command usage. Type 'install help' for a list of available commands." -ForegroundColor Red -Log
                $baseCommandProcessed = $true
            }
            "^changelog$" {
                Write-CCLSHost "Wrong command usage. Type 'changelog help' for a list of available options." -ForegroundColor Red -Log
                $baseCommandProcessed = $true
            }
        }
        
        # If a base command was processed, skip the regular command processing
        if ($baseCommandProcessed) {
            continue
        }
        
        # Regular command processing with parameters
        switch -Regex ($command.ToLower()) {
            # Your existing command handlers here
            "^check$" {
                Test-SystemRequirements
            }
            "^exit$|^quit$" {
                $running = $false
                Write-CCLSHost "Thank you for using the CCLS Games CLI Tool. Goodbye!" -ForegroundColor Cyan -Log
            }
            "^clear$|^cls$" {
                Clear-ConsoleScreen
            }
            "^extract(?:\s+([^-]+))(?:\s+-y)?$" {
                $fileIdentifier = $matches[1].Trim()
                $skipConfirmation = $command -match "-y$"
                Start-GameExtraction -FileIdentifier $fileIdentifier -SkipConfirmation:$skipConfirmation
            }
            "^install(?:\s+(.+))?$" {
                $utilityName = if ($matches.Count -gt 1) { $matches[1] } else { "" }
                Install-Utility -UtilityName $utilityName
            }
            "^version$" {
                Show-Version
            }
            "^update$" {
                Update-CliTool
            }
            "^setup$" {
                Start-Setup
            }
            "^search\s+(c[gb]\d{4})$" {
                $id = $matches[1]
                Search-Game -id $id
            }
            "^get\s+(c[gb]\d{4})(?:\s+-y)?$" {
                $id = $matches[1]
                $skipConfirmation = $command -match "-y$"
                Get-Game -id $id -SkipConfirmation:$skipConfirmation
            }
            "^search\s+library$|^library$" {
                Get-GamesList
            }
            "^list\s+games$" {
                Get-InstalledGames
            }
            "^list\s+games\s+-d$" {
                Get-InstalledGames -Detailed
            }
            "^list\s+game\s+(.+?)(?:\s+(?:-d|-tree))*$" {
                $gameName = $matches[1].Trim()
                $detailed = $command -match "\s+-d\b"
                $tree = $command -match "\s+-tree\b"
                Get-GameInfo -GameName $gameName -Detailed:$detailed -Tree:$tree
            }
            "^del\s+(.+?)(?:\s+-y)?$" {
                $gameName = $matches[1]
                $force = $command -match "-y$"
                Remove-Game -GameName $gameName -Force:$force
            }
            "^changelog\s+(.+)$" {
                $versionParam = $matches[1].Trim()
                Show-Changelog -Version $versionParam
                $commandProcessed = $true
            }
            "^logout$" {
                $running = $false
                Write-CCLSHost "Logging out..." -ForegroundColor Cyan -Log
            }
            "^forget$" {
                if (Test-Path $credentialsFile) {
                    Remove-Item -Path $credentialsFile -Force
                    $settings = Initialize-Settings
                    $settings.RememberLogin = $false
                    Save-Settings -settings $settings
                    Write-CCLSHost "Stored credentials have been removed." -ForegroundColor Green -Log
                }
                else {
                    Write-CCLSHost "No stored credentials found." -ForegroundColor Yellow -Log
                }
            }
            default {
                # Extract the base command from the input (first word)
                $baseCommand = $command.Trim().Split()[0].ToLower()
                
                # Known base commands that have help available
                $knownCommands = @('search', 'get', 'extract', 'list', 'del', 'install')
                
                if ($knownCommands -contains $baseCommand) {
                    # If it's a known command with incorrect parameters
                    Write-CCLSHost "Wrong command usage. Type '$baseCommand help' for a list of available commands." -ForegroundColor Red -Log
                } else {
                    # Completely unknown command
                    Write-CCLSHost "Unknown command. Type 'help' for a list of all available commands." -ForegroundColor Red -Log
                }
            }
        }
    }
}

# Add a line to log script completion
function End-Logging {
    $endTime = Get-Date
    "CCLS Games CLI Session ended at $endTime, duration: $(($endTime - [DateTime]::ParseExact($script:sessionStartTime, 'yyyy-MM-dd_HH-mm-ss', $null)).ToString())" | Out-File -FilePath $script:logFile -Append
}

# Register script exit event to ensure logging is completed
Register-EngineEvent -SourceIdentifier ([System.Management.Automation.PsEngineEvent]::Exiting) -Action {
    End-Logging
} | Out-Null

# Function to handle the CLI startup
function Start-CclsCliTool {
    # Initialize script variables
    $script:versionChanged = $false
    $script:previousVersion = $null
    
    Write-CCLSHost "Hello and welcome to the CCLS Games CLI Tool" -ForegroundColor Green -Log
    Write-CCLSHost "Before proceeding to using this software you will need to sign in." -Log
    Write-CCLSHost "If you do not have an account already please go to $baseUrl/login.php?signup to register a new account." -ForegroundColor Cyan -Log
    
    # Load settings (this will set versionChanged flag if needed)
    $settings = Initialize-Settings
    
    # Try auto-login if remember login is enabled
    $loginResult = @{ Success = $false }
    if ($settings.RememberLogin) {
        $loginResult = Start-AutoLogin
    }
    
    # If auto-login failed or is disabled, do manual login
    if (-not $loginResult.Success) {
        $loginResult = Start-ManualLogin
    }
    
    # If login succeeded, show main interface
    if ($loginResult.Success) {
        # Show welcome message
        Write-CCLSHost "Welcome to CCLS Games CLI Tool, $($loginResult.Username)!" -ForegroundColor Green -Log
        
        # Check if version has changed and show notification
        if ($script:versionChanged) {
            $versionInfo = Test-VersionUpdate
            $currentVersion = $versionInfo.CurrentVersion
            Write-CCLSHost "Welcome to $currentVersion! Type 'changelog latest' to view the changes made." -ForegroundColor Green -Log
        }
        
        # Show appropriate message based on setup status
        if ($settings.HasCompletedSetup) {
            Write-CCLSHost "Type 'help' for a list of available commands." -ForegroundColor Cyan -Log
        }
        else {
            Write-CCLSHost "ALERT, type command 'setup' to set critical values before downloading." -ForegroundColor Red -Log
        }
        
        Start-CommandInterface -username $loginResult.Username
    }
    else {
        Write-CCLSHost "Login failed. Press any key to exit..." -ForegroundColor Red -Log
        $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    }
}

# Format a file size in bytes to a human-readable string
function Format-Size {
    param (
        [long]$Size
    )
    
    if ($Size -ge 1GB) {
        return "{0:N2} GB" -f ($Size / 1GB)
    }
    elseif ($Size -ge 1MB) {
        return "{0:N2} MB" -f ($Size / 1MB)
    }
    elseif ($Size -ge 1KB) {
        return "{0:N2} KB" -f ($Size / 1KB)
    }
    else {
        return "$Size B"
    }
}

# Start the application
Try {
    Start-CclsCliTool
}
Finally {
    # Ensure logging is completed even if script exits unexpectedly
    End-Logging
}