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 and logging
$script:progressInitialized = $false
$script:topProgressLine = $null
$script:logFile = $null
$script:sessionStartTime = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"

# 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 {
    if (-not (Test-Path $settingsFile)) {
        # Create default settings file
        $defaultSettings = @{
            RememberLogin = $false
            DownloadPath = ".\downloads"
            TempDownloadPath = ".\tmp"
            HasCompletedSetup = $false
        }
        $defaultSettings | ConvertTo-Json | Set-Content -Path $settingsFile
    }
    
    # Load settings
    $settings = Get-Content -Path $settingsFile | ConvertFrom-Json
    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
            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
                
                # 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
    }
}

# Search for game information by CG number
function Search-Game($cgNumber) {
    # Validate CG number format
    if ($cgNumber -notmatch "^cg\d{4}$") {
        Write-CCLSHost "Invalid CG number format. Please use format 'cg0000'." -ForegroundColor Red -Log
        return
    }
    
    try {
        # Construct the URL for the game JSON file
        $gameJsonUrl = "$cliApiUrl/search.php?id=$cgNumber"
        
        # Attempt to fetch the game information
        $params = @{
            Uri = $gameJsonUrl
            Method = "GET"
            Headers = @{
                "User-Agent" = "CCLS-CLI/1.0"
            }
        }
        
        Write-CCLSHost "#Searching for game information..." -Log
        
        # Fetch game 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
            }
            
            $gameInfo = $response
        }
        catch {
            Write-CCLSHost "Error fetching game information: $($_.Exception.Message)" -ForegroundColor Red -Log
            return
        }
        
        # Display game information in a formatted way
        Write-CCLSHost "`n==========================================================" -ForegroundColor DarkGray -Log
        Write-CCLSHost "Game Information for $($gameInfo.name) ($($gameInfo.id))" -ForegroundColor Green -Log
        Write-CCLSHost "==========================================================" -ForegroundColor DarkGray -Log
        
        Write-CCLSHost "`nDescription:" -ForegroundColor Cyan -Log
        Write-CCLSHost $gameInfo.description -Log
        
        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 }
        }
        
        Write-CCLSHost "`nDetails:" -ForegroundColor Cyan -Log
        if ($gameInfo.size) { Write-CCLSHost "Size: $($gameInfo.size)" -Log }
        if ($gameInfo.version -and $gameInfo.version -ne "") { Write-CCLSHost "Version: $($gameInfo.version)" -Log }
        
        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 }
        }
        
        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
        }
        
        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
                }
            }
        }
        
        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 game 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 Update-DownloadProgress {
    param (
        [long]$bytesReceived,
        [long]$totalBytes,
        [int]$progressPercentage,
        [TimeSpan]$elapsedTime,
        [double]$downloadSpeed,
        [string]$gameName,
        [string]$gameId
    )
    
    # Calculate values for display
    $downloadSpeedMbps = [math]::Round($downloadSpeed / 1024 / 1024 * 8, 2)
    $remainingBytes = $totalBytes - $bytesReceived
    $estimatedTimeRemaining = if ($downloadSpeed -gt 0) { 
        [TimeSpan]::FromSeconds([math]::Floor($remainingBytes / $downloadSpeed)) 
    } else { 
        [TimeSpan]::Zero 
    }
    
    # Format sizes for display
    $bytesSoFar = if ($bytesReceived -ge 1GB) {
        "{0:N2} GB" -f ($bytesReceived / 1GB)
    } elseif ($bytesReceived -ge 1MB) {
        "{0:N2} MB" -f ($bytesReceived / 1MB)
    } elseif ($bytesReceived -ge 1KB) {
        "{0:N2} KB" -f ($bytesReceived / 1KB)
    } else {
        "$bytesReceived B"
    }
    
    $totalSize = if ($totalBytes -ge 1GB) {
        "{0:N2} GB" -f ($totalBytes / 1GB)
    } elseif ($totalBytes -ge 1MB) {
        "{0:N2} MB" -f ($totalBytes / 1MB)
    } elseif ($totalBytes -ge 1KB) {
        "{0:N2} KB" -f ($totalBytes / 1KB)
    } else {
        "$totalBytes B"
    }
    
    $estimatedTime = if ($estimatedTimeRemaining.TotalHours -ge 1) {
        "{0:D2}:{1:D2}:{2:D2}" -f $estimatedTimeRemaining.Hours, $estimatedTimeRemaining.Minutes, $estimatedTimeRemaining.Seconds
    } else {
        "{0:D2}:{1:D2}" -f $estimatedTimeRemaining.Minutes, $estimatedTimeRemaining.Seconds
    }
    
    $elapsedTimeStr = if ($elapsedTime.TotalHours -ge 1) {
        "{0:D2}:{1:D2}:{2:D2}" -f $elapsedTime.Hours, $elapsedTime.Minutes, $elapsedTime.Seconds
    } else {
        "{0:D2}:{1:D2}" -f $elapsedTime.Minutes, $elapsedTime.Seconds
    }
    
    # Create the progress information lines
    $lines = @(
        "Progress: $progressPercentage%",
        "Downloaded: $bytesSoFar of $totalSize",
        "Speed: $downloadSpeedMbps Mbps",
        "Time Elapsed: $elapsedTimeStr",
        "Estimated Time Remaining: $estimatedTime",
        "Press Ctrl+C to cancel the download"
    )
    
    # Log the progress
    foreach ($line in $lines) {
        $line | Out-File -FilePath $script:logFile -Append
    }
    
    # First time initialization
    if (-not $script:progressInitialized) {
        # Mark this as our first time
        $script:progressInitialized = $true
        
        # Print a header for the download progress - FIXED to properly display game name
        Write-CCLSHost "`n[Download Progress - $gameName ($gameId)]" -ForegroundColor Green
        
        # Create the initial progress block
        foreach ($line in $lines) {
            if ($line -eq $lines[-1]) {
                Write-CCLSHost $line -ForegroundColor Red
            } else {
                Write-CCLSHost $line -ForegroundColor Yellow
            }
        }
        
        # Store the beginning line number for future updates
        # Note: We're using the current cursor position - lines count to get the top line
        $script:topProgressLine = $host.UI.RawUI.CursorPosition.Y - $lines.Count
    }
    else {
        # Save current cursor position
        $currentPosition = $host.UI.RawUI.CursorPosition
        
        # Update each line of the progress display in place
        for ($i = 0; $i -lt $lines.Count; $i++) {
            # Set cursor to beginning of this progress line
            $host.UI.RawUI.CursorPosition = New-Object System.Management.Automation.Host.Coordinates 0, ($script:topProgressLine + $i)
            
            # Clear the entire line first
            $lineWidth = $host.UI.RawUI.BufferSize.Width - 1
            Write-Host (" " * $lineWidth) -NoNewline
            
            # Reset cursor and write the content
            $host.UI.RawUI.CursorPosition = New-Object System.Management.Automation.Host.Coordinates 0, ($script:topProgressLine + $i)
            
            if ($i -eq ($lines.Count - 1)) {
                # Last line in red
                Write-Host $lines[$i] -ForegroundColor Red
            } else {
                # Other lines in yellow
                Write-Host $lines[$i] -ForegroundColor Yellow
            }
        }
        
        # Restore cursor position
        $host.UI.RawUI.CursorPosition = $currentPosition
    }
}

# Function to properly reset the progress display when download completes or fails
function Reset-ProgressDisplay {
    # Only do something if we've initialized a progress display
    if ($script:progressInitialized) {
        # Save current cursor position
        $currentPosition = $host.UI.RawUI.CursorPosition

        # Move to one line after the progress display to add completion message
        $host.UI.RawUI.CursorPosition = New-Object System.Management.Automation.Host.Coordinates 0, ($script:topProgressLine + 6)
        
        # Reset the initialization flag
        $script:progressInitialized = $false
        $script:topProgressLine = $null
        
        # We don't reset cursor position here because we want to continue output from the end of progress display
    }
}

# Function to call before starting a new download
function Initialize-DownloadTracking {
    # Ensure we always start fresh
    $script:progressInitialized = $false
    $script:topProgressLine = $null
    
    # Reset global variables used by event handlers
    $global:startTime = $null
    $global:lastUpdateTime = $null
}

# Function to download and extract a game
function Get-Game($cgNumber) {
    # Initialize progress tracking for a fresh download
    Initialize-DownloadTracking
    
    # Validate CG number format
    if ($cgNumber -notmatch "^cg\d{4}$") {
        Write-CCLSHost "Invalid CG number format. Please use format 'cg0000'." -ForegroundColor Red -Log
        return
    }
    
    # Check if setup has been completed
    $settings = Initialize-Settings
    if (-not $settings.HasCompletedSetup) {
        Write-CCLSHost "ALERT, you must run the 'setup' command before downloading games." -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
        }
    }
    
    # Fetch game download information
    try {
        $gameInfoUrl = "$cliApiUrl/get.php?id=$cgNumber"
        
        $params = @{
            Uri = $gameInfoUrl
            Method = "GET"
            Headers = @{
                "User-Agent" = "CCLS-CLI/1.0"
            }
        }
        
        Write-CCLSHost "#Fetching game download information..." -Log
        
        $response = Invoke-RestMethod @params
        
        if (-not $response.success) {
            Write-CCLSHost "Error: $($response.message)" -ForegroundColor Red -Log
            return
        }
        
        $gameName = $response.name
        $gameId = $response.id
        $downloadUrl = $response.download_url
        $gameSize = $response.size
        
        # Create download file name from URL
        $fileName = Split-Path -Path $downloadUrl -Leaf
        if ([string]::IsNullOrEmpty($fileName)) {
            $fileName = "$gameId.7z"
        }
        
        $downloadPath = Join-Path -Path $settings.TempDownloadPath -ChildPath $fileName
        
        # Confirm download with user
        Write-CCLSHost "==========================================================" -ForegroundColor DarkGray -Log
        Write-CCLSHost "Game Download: $gameName ($gameId)" -ForegroundColor Green -Log
        Write-CCLSHost "==========================================================" -ForegroundColor DarkGray -Log
        Write-CCLSHost "Size: $gameSize" -ForegroundColor Yellow -Log
        Write-CCLSHost "Download URL: $downloadUrl" -ForegroundColor Cyan -Log
        Write-CCLSHost "Download Location: $downloadPath" -ForegroundColor Cyan -Log
        Write-CCLSHost "Extract Location: $($settings.DownloadPath)" -ForegroundColor Cyan -Log
        Write-CCLSHost "ALERT, the get command will start the downloading process of the game specified, to stop it do 'Ctrl C'" -ForegroundColor Red -Log
        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
        }
        
        # Set global variables that will be used for the download progress display
        # Make sure we're explicitly setting these so they're accessible in the event handlers
        $global:gameNameForProgress = $gameName
        $global:gameIdForProgress = $gameId
        
        # Start download
        $webClient = New-Object System.Net.WebClient
        $startTime = Get-Date
        $lastUpdateTime = $startTime
        
        # Set global variables for use in event handlers
        $global:startTime = $startTime
        $global:lastUpdateTime = $lastUpdateTime
        
        # Create event handlers for download progress
        $downloadProgressEvent = Register-ObjectEvent -InputObject $webClient -EventName DownloadProgressChanged -Action {
            $bytesReceived = $EventArgs.BytesReceived
            $totalBytes = $EventArgs.TotalBytesToReceive
            $progressPercentage = $EventArgs.ProgressPercentage
            $currentTime = Get-Date
            
            # Only update display every 500ms to avoid console flicker
            if (($currentTime - $global:lastUpdateTime).TotalMilliseconds -ge 500) {
                $global:lastUpdateTime = $currentTime
                
                $elapsedTime = $currentTime - $global:startTime
                $elapsedSeconds = [math]::Floor($elapsedTime.TotalSeconds)
                
                $downloadSpeed = if ($elapsedSeconds -gt 0) { $bytesReceived / $elapsedSeconds } else { 0 }
                
                # Use the new progress update function - PASSING PROPER GAME NAME AND ID
                Update-DownloadProgress -bytesReceived $bytesReceived -totalBytes $totalBytes `
                    -progressPercentage $progressPercentage -elapsedTime $elapsedTime `
                    -downloadSpeed $downloadSpeed -gameName $global:gameNameForProgress -gameId $global:gameIdForProgress
            }
        }
        
        $downloadCompletedEvent = Register-ObjectEvent -InputObject $webClient -EventName DownloadFileCompleted -Action {
            # Reset progress display properly
            Reset-ProgressDisplay
            
            Write-CCLSHost "#Download completed!" -Log
            Write-CCLSHost "#Starting extraction process..." -Log
            
            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
                    
                    # 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
                    Write-CCLSHost "#Loaded DownloadPath: $downloadPath" -Log
                    
                    # 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 or ensure it's in one of these locations:" -ForegroundColor Yellow -Log
                            Write-CCLSHost "  - C:\Program Files\7-Zip\7z.exe" -ForegroundColor Yellow -Log
                            Write-CCLSHost "  - C:\Program Files (x86)\7-Zip\7z.exe" -ForegroundColor Yellow -Log
                            Write-CCLSHost "  - .\7zip\7z.exe" -ForegroundColor Yellow -Log
                            return
                        }
                    }
                    
                    # Get all .7z files in the temp download path
                    Write-CCLSHost "#Searching for .7z files in: $tempDownloadPath" -Log
                    $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
                    
                    # Process each .7z file
                    foreach ($file in $7zFiles) {
                        $filePath = $file.FullName
                        
                        # Extract the file
                        Write-CCLSHost "Extracting: $filePath to $downloadPath" -ForegroundColor Cyan -Log
                        & "$7zipPath" x "$filePath" -o"$downloadPath" -y
                        
                        # Check if extraction was successful
                        if ($LASTEXITCODE -eq 0) {
                            # Delete the original .7z file
                            Write-CCLSHost "Extraction successful. Deleting original file: $filePath" -ForegroundColor Green -Log
                            Remove-Item -Path $filePath -Force
                        } else {
                            Write-CCLSHost "Failed to extract: $filePath. Skipping deletion." -ForegroundColor Red -Log
                        }
                    }
                    
                    Write-CCLSHost "#All .7z files have been processed." -Log
                    Write-CCLSHost "Go to $downloadPath to play the game." -ForegroundColor Cyan -Log
                }
                
                # Call the extraction function
                Start-GameExtraction
            }
            catch {
                Write-CCLSHost "An error occurred during extraction: $($_.Exception.Message)" -ForegroundColor Red -Log
                Write-CCLSHost "Error details: $($_.Exception.StackTrace)" -ForegroundColor Red -Log
            }
        }
        
        # Start the download
        try {
            $webClient.DownloadFileAsync([Uri]$downloadUrl, $downloadPath)
            
            # Wait for download to complete
            while ($webClient.IsBusy) {
                Start-Sleep -Milliseconds 100
            }
        }
        catch {
            # Reset the progress display
            Reset-ProgressDisplay
            Write-CCLSHost "An error occurred during download: $($_.Exception.Message)" -ForegroundColor Red -Log
        }
        finally {
            # Clean up event handlers
            if ($downloadProgressEvent) { Unregister-Event -SourceIdentifier $downloadProgressEvent.Name }
            if ($downloadCompletedEvent) { Unregister-Event -SourceIdentifier $downloadCompletedEvent.Name }
            $webClient.Dispose()
        }
    }
    catch {
        Write-CCLSHost "An error occurred: $($_.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
    
    # 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 to list all available games
function Get-GamesList {
    try {
        # Construct the URL for the game list API
        $gamesListUrl = "$cliApiUrl/list.php"
        
        $params = @{
            Uri = $gamesListUrl
            Method = "GET"
            Headers = @{
                "User-Agent" = "CCLS-CLI/1.0"
            }
        }
        
        Write-CCLSHost "#Fetching game library..." -Log
        
        # Fetch game 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
                return
            }
            
            # 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
            }
            
            Write-CCLSHost "Use 'search [cgnumber]' to get detailed information about a specific game." -ForegroundColor Yellow -Log
            
            # REMOVED: The following lines that were causing the extra keypress requirement
            # Write-CCLSHost "#Press any key to return to the main menu..." -Log
            # $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
        }
        catch {
            Write-CCLSHost "Error fetching game library: $($_.Exception.Message)" -ForegroundColor Red -Log
            # Also removed the keypress requirement here
        }
    }
    catch {
        Write-CCLSHost "An error occurred while processing game library: $($_.Exception.Message)" -ForegroundColor Red -Log
        # Also removed the keypress requirement here
    }
}

function Start-CclsCliTool {
    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
    
    $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) {
        # Notice we removed the "`n`n" at the beginning of the welcome message
        Write-CCLSHost "Welcome to CCLS Games CLI Tool, $($loginResult.Username)!" -ForegroundColor Green -Log
        
        # Show appropriate message based on setup status
        $settings = Initialize-Settings
        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")
    }
}

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
    
    # Optionally, display a minimal header after clearing
    Write-CCLSHost "CCLS Games CLI Tool" -ForegroundColor Green -Log
}

# Function to format file size in a human-readable way
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"
    }
}

# 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
}

# Function to list games in the download directory
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) {
            if ($Detailed) {
                # Get folder size for detailed view
                $size = Get-FolderSize -Path $folder.FullName
                $totalSize += $size
                $sizeFormatted = Format-Size -Size $size
                
                # Display with size
                Write-CCLSHost "$($folder.Name) - $sizeFormatted" -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 unlimited file tree depth)
function Get-GameInfo {
    param (
        [string]$GameName,
        [switch]$Detailed
    )
    
    # 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 Yellow -Log
        return
    }
    
    # Get game size
    $size = Get-FolderSize -Path $gamePath
    $sizeFormatted = Format-Size -Size $size
    
    # Header
    Write-CCLSHost "`nGame Information: $GameName" -ForegroundColor Green -Log
    Write-CCLSHost "=======================" -ForegroundColor Green -Log
    Write-CCLSHost "Location: $gamePath" -Log
    Write-CCLSHost "Size: $sizeFormatted" -Log
    
    # If detailed view, show file tree
    if ($Detailed) {
        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 Yellow -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
    }
}

# Alternative implementation using a direct embedding approach if web fetch doesn't work
function Show-Dirty-Secret {
    try {
        $moosArt = Get-Content -Path "moos.txt" -Raw -Encoding UTF8
        
        # If we can't get the file, embed a basic version of the art
        if ([string]::IsNullOrEmpty($moosArt)) {
            # Embed the ASCII art directly from moos.txt
            $moosArt = @'
    ╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╣╣╣
    ╢╢╣╣╣╣╢╣▓╣▓▓▓▓╣╣╢╢╢╢╢╢╢╢╢╢╢╢╢╢╣╢╣╣╢╣╣╣╣╣╢╢╢╢╢╢╢╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢╢╢╢
    ╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╣╢╢╣╣╣╣╣╣▒▒▒▒▒▒▒╢▒╢╢╢╣╢╢╢╢╢╢╢╢╢╢╢╢╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢╢╢╢
    ▒╢╣╢╢╢╢╢╢╣╣╣╣╣╣╣╣╣╢╣╢╢╢▒╢▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒╢╣╣╣╢╢╣╢╢╢╢╢╢╢╢╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╣╢╢╢╣
    ▒▒▒╢╢╢╣╣╣╣╣╣╣╣╢╣▒╢▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒╣╣╣╣╣╢╣╢╢╢╢╢╢╢╢╢╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╢╢╢╢╢
    ▒▒▒▒╣╣╢╣╣╣╣╣╣╣╣▒╣╣╣╣▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒╣╣╣╣╣╣╢╣╢╢╢╢╢╢╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╢╢╢╣
    ▒▒▒▒▒▒╣╣╣╣╢╣╣╣╣╣╣╣╣▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒╣╣▒╢╣╣╣╣╣╣╣╣╣╣╢╢╢╢╢╢╢╢╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢
    ▒▒▒▒▒╣╣╢╣╣╣╢╣╣╣╣╣╣╣╣╣╣╣╣╣▒▒▒╣▒╣╣╣╣╢╣╣╣╣╣╣╢╣╣╣╢╢╢╢╢╢╢╢╢╢╢╢╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╢
    ▒▒▒▒▒▒╣╣╣╣╢╣╣╢╣╣╣╣╣╣╣╣╣╣╣╣╣▒╣╣╣╣╣╣╣╣╣╣╢╣╣╣╣╣╢╢╢╢╢╢╣╢╢╢╢╢╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╢╢
    ▒▒▒▒╣╣╣╣╣╣╢╢╢╣╢╣╣╣╣╣╣╣╣╣╣╣╣╣╣╣╣╣╣╣╣╢╣╣╢╣╢╢╣╣╣╢╣╢╢╢╢╢╢╢╢╢╢╢╣╣╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╣
    ▒▒▒▒╢╣╢╣╢╢╢╢╣╢╣╣╣╢╣╢╢╣╣╣╣╣╣╣╣╣╣╢╢╣╢╣╣╣╣╣╣╢╢╢╣╢╢╢╢╢╢╢╢╢╢╢╣╣╣╣╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
    ▒▒▒▒▒╢╣╢╣╣╢╢╢╢╢╣╢╢╢╢╣╣╣╢╢╣╣╣╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╣╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
    ▒▒▒▒▒╣╢╢╢╢╢╢╢╢╢╣╢╢╢╢╢╢╣╢╢╣╢╢╢╢╢╢╣╣╣╣╣╣▓▓╣╣╣╣╢╢╢╢╢╢╣╣╢╣╣▓╣╣╢╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
    ▒▒▒╢╢╢╢╢╢╢╢╢╣╢╢╢╢╢╢╢╣╢╣╢╢╢╢╢╢╢╢╣╢╣▓▓╣╢╢╢╢╣╢╢╢╢╢╢╣╢╣╣╣╢╣▓▓▓╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣
    ▒▒╢╢╢╣╣╣╣╣▓▓╣▓▓▓╣╣╢╢╢╢╢╢╢╢╢╢╢╢╢╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╣▓╣╣╣╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢
    ▒▒▒╢╢╢╢╢╢╣▓▓╣▓▓▓▓╣╣╣╢╢╢╢╢╢╢╢╢╢╣╣╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╣▓╣╣▓▓▓▓▓▓▓▓▓▓▓▓╣╣▓▓▓▓▓╣╢
    ▒▒▒▒╢╢╢╣▓▓▓▓▓▓▓▓▓╣╣╣╢╢╢╢╢╢╢╢╢╢╢╢╢╢╣╣╣╣╣▓▓▓▓▓▓▓▓▓▓╣╢╢╣╣╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢╢▓▓▓╢╢╢
    ▒▒▒▒▒▒╢╢╢╢▓▓▓▓▓╣▓▓▓╣╣╣╢╢╢╢╢╢╢╣╣╢╣╢╢▓▓▓▓▓▓▓▓╣╢╣╣╣╣╣╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢▓▓╣╢╢╢╢
    ╢╣╣▒╢▒╢╢╢╢╢╢╢╣╣▓▓▓▓▓╣╢╢╢╢╢╣╢╢╢╢╢╣╣╢╢╢╢╢╣╣╣╣╢╢╢╣╣╢╣╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢╣▓╣╢╢╢╢╢
    ▒▒╢╢▒╣╢╢╢╢╢╣╣▓▓╣▓▓╣╢╢╢╢╢╢╣╣╣▓▓╣╣╣╣╢╢╣╣╢╢╢╣╣╣╣╣╣╣╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢╢╢╢╢╢╢╢╢╢
    ╣╣╣╣╣╣╣╢╢╢╢╣╣╣╣╣╣╣╢╢╣╢╢╢╣▓▓╣▓▓▓╣▓▓▓▓▓╣╣╣▓╣╢╢╢╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╣╣╢╢╢╢╢╢╢╢
    ╣╣╣╣╣╣╣╢╢╢╢╣╣╣▓▓╣╣╢╣╣╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢╣╢╢
    ╣╣╣╣╣╢╢╣╣╢╢╢╣▓▓▓▓▓╣╣╢╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╣╣
    ╢╣╣╣╢╣╣╢╣╢╢╢╢╣▓▓▓▓╣╣╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
    ╢╢╢╢╢╢╢╢▓▓╣╢╢╢▓▓▓▓▓╣╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
    ▓▓╣╣╢▓▓▓▓▓▓╣╢╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
    ▓▓▓╣╣▓▓▓▓▓▓▓▓╣╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
    ▓▓▓╣╢▓▓▓▓▓▓▓▓▓▓╣╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
    ▓▓▓▓╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
    ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
    ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
    ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
    ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
    ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
    ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
    ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
'@
        }
        
        # Display the art directly
        Write-Host $moosArt -ForegroundColor Cyan
        
    }
    catch {
        Write-CCLSHost "moos no no no no no" -ForegroundColor Yellow -Log
        Write-CCLSHost "#Error details: $($_.Exception.Message)" -ForegroundColor Red -Log -NoConsole
    }
}

# Modified Start-CommandInterface function to include the secret command
function Start-CommandInterface($username) {
    $running = $true
    while ($running) {
        Write-CCLSHost "CCLS>" -ForegroundColor Yellow -NoNewline -Log
        $command = Read-Host
        Write-CCLSHost "$command" -NoConsole -Log
        
        switch -Regex ($command.ToLower()) {
            "^exit|^quit" {
                $running = $false
                Write-CCLSHost "Thank you for using the CCLS Games CLI Tool. Goodbye!" -ForegroundColor Cyan -Log
            }
            "^clear|^cls" {
                # Call the clear screen function
                Clear-ConsoleScreen
            }
            # Secret command that isn't shown in help
            "^moos$" {
                # Call the moos function
                Show-Dirty-Secret
            }
            "^help" {
                Write-CCLSHost "Available Commands:" -ForegroundColor Green -Log
                Write-CCLSHost "  help                - Show this help message" -Log
                Write-CCLSHost "  clear, cls          - Clear the console screen" -Log
                Write-CCLSHost "  setup               - Configure download directories" -Log
                Write-CCLSHost "  search              - Search for game information by CG number" -Log
                Write-CCLSHost "  search library      - List all available games for download" -Log
                Write-CCLSHost "  get                 - Download and install a game by CG number" -Log
                Write-CCLSHost "  list games          - List installed games (names only)" -Log
                Write-CCLSHost "  list games -d       - List installed games with sizes" -Log
                Write-CCLSHost "  list game [name]    - Show info about a specific game" -Log
                Write-CCLSHost "  list game [name] -d - Show detailed info about a specific game with file tree" -Log
                Write-CCLSHost "  del [name]          - Delete a game (with confirmation)" -Log
                Write-CCLSHost "  del [name] -y       - Delete a game without confirmation" -Log
                Write-CCLSHost "  exit, quit          - Exit the application" -Log
                Write-CCLSHost "  logout              - Log out and exit" -Log
                Write-CCLSHost "  forget              - Remove stored credentials" -Log
            }
            "^setup" {
                Start-Setup
            }
            "^search$" {
                Write-CCLSHost "To use the search command please provide a valid CG number in this format 'search cg0000'" -ForegroundColor Cyan -Log
                Write-CCLSHost "To get the CG number of a game, go to the main games page and click on any game, then check" -ForegroundColor Cyan -Log
                Write-CCLSHost "the URL 'https://games.ccls.icu/game.php?id=cg0000' and the 'cg0000' part in URL is the CG number" -ForegroundColor Cyan -Log
            }
            "^search\s+(cg\d{4})$" {
                $cgNumber = $matches[1]
                Search-Game -cgNumber $cgNumber
            }
            "^get$" {
                Write-CCLSHost "To use the get command please provide a valid CG number in this format 'get cg0000'" -ForegroundColor Cyan -Log
                Write-CCLSHost "To get the CG number of a game, go to the main games page and click on any game, then check" -ForegroundColor Cyan -Log
                Write-CCLSHost "the URL 'https://games.ccls.icu/game.php?id=cg0000' and the 'cg0000' part in URL is the CG number." -ForegroundColor Cyan -Log
                Write-CCLSHost "ALERT, the get command will start the downloading process of the game specified, to stop it do 'Ctrl C'" -ForegroundColor Red -Log
            }
            "^get\s+(cg\d{4})$" {
                $cgNumber = $matches[1]
                Get-Game -cgNumber $cgNumber
            }
            "^search\s+library$|^library$" {
                Get-GamesList
            }
            "^list\s+games$" {
                # List games with minimal detail
                Get-InstalledGames
            }
            "^list\s+games\s+-d$" {
                # List games with detailed information
                Get-InstalledGames -Detailed
            }
            "^list\s+game\s+(.+?)(?:\s+-d)?$" {
                $gameName = $matches[1]
                $detailed = $command -match "-d$"
                
                # Show information about a specific game
                Get-GameInfo -GameName $gameName -Detailed:$detailed
            }
            "^del\s+(.+?)(?:\s+-y)?$" {
                $gameName = $matches[1]
                $force = $command -match "-y$"
                
                # Delete the specified game
                Remove-Game -GameName $gameName -Force:$force
            }
            "^logout" {
                $running = $false
                Write-CCLSHost "Logging out..." -ForegroundColor Cyan -Log
                # Clear the current session but keep credentials if they exist
            }
            "^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 {
                Write-CCLSHost "Unknown command. Type 'help' for a list of 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

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