scripts/modules/prerequisites/docker/install-docker.ps1

# strangeloop Setup - Docker Installation Module
# Version: 1.0.0


param(
    [switch]${test-only},
    [switch]$AutoStart,
    [switch]$RequiresWSL,
    [switch]${what-if}
)

# Import shared modules
$SharedPath = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent | Join-Path -ChildPath "shared"
. "$SharedPath\write-functions.ps1"
. "$SharedPath\test-functions.ps1"

function Test-Docker {
    param(
        [switch]$AutoStart
    )
    
    try {
        Write-Info "Testing Docker installation..."
        
        # Check if Docker command is available
        if (-not (Test-Command "docker")) {
            Write-Warning "Docker command not found"
            return $false
        }
        
        # Check Docker version
        $dockerVersion = docker --version 2>$null
        if (-not $dockerVersion) {
            Write-Warning "Could not get Docker version"
            return $false
        }
        
        Write-Info "Docker client found: $dockerVersion"
        
        # Test Docker daemon connection
        Write-Info "Testing Docker daemon connection..."
        $dockerInfo = docker info 2>$null
        if ($LASTEXITCODE -ne 0) {
            Write-Warning "Docker daemon is not running"
            
            # Try to start Docker Desktop if AutoStart is enabled
            if ($AutoStart) {
                Write-Info "Attempting to start Docker Desktop..."
                try {
                    $dockerDesktopPath = "C:\Program Files\Docker\Docker\Docker Desktop.exe"
                    if (Test-Path $dockerDesktopPath) {
                        Start-Process $dockerDesktopPath -WindowStyle Hidden
                        Write-Info "Docker Desktop startup initiated. Waiting for daemon to start..."
                        
                        # Wait for Docker daemon to start (up to 60 seconds)
                        $timeout = 60
                        $elapsed = 0
                        $interval = 3
                        
                        while ($elapsed -lt $timeout) {
                            Start-Sleep -Seconds $interval
                            $elapsed += $interval
                            
                            $dockerInfo = docker info 2>$null
                            if ($LASTEXITCODE -eq 0) {
                                Write-Success "Docker daemon started successfully"
                                Write-Success "Docker is properly installed and running: $dockerVersion"
                                return $true
                            }
                            
                            Write-Info "Waiting for Docker daemon... ($elapsed/$timeout seconds)"
                        }
                        
                        Write-Warning "Docker daemon did not start within $timeout seconds"
                        Write-Info "Docker Desktop may still be starting. Please wait a few more minutes."
                        return $false
                    } else {
                        Write-Warning "Docker Desktop executable not found at expected location"
                        return $false
                    }
                } catch {
                    Write-Warning "Failed to start Docker Desktop: $($_.Exception.Message)"
                    return $false
                }
            } else {
                Write-Info "Docker is installed but daemon is not running. Use -AutoStart to automatically start Docker Desktop."
                return $false
            }
        } else {
            # Docker daemon is running, test basic functionality
            Write-Info "Testing Docker functionality..."
            try {
                # Test if we can run a simple container
                $testResult = docker run --rm hello-world 2>$null
                if ($LASTEXITCODE -eq 0) {
                    Write-Success "Docker functionality test passed"
                } else {
                    Write-Warning "Docker functionality test failed, but daemon is running"
                }
            } catch {
                Write-Warning "Could not test Docker functionality: $($_.Exception.Message)"
            }
            
            Write-Success "Docker is properly installed and running: $dockerVersion"
            return $true
        }
        
    } catch {
        Write-Warning "Error testing Docker: $($_.Exception.Message)"
        return $false
    }
}

function Set-DockerWSLIntegration {
    <#
    .SYNOPSIS
    Configures Docker Desktop for WSL integration
    
    .DESCRIPTION
    Enables WSL 2 based engine and default WSL distro integration in Docker Desktop settings
    
    .PARAMETER test-only
    Only test the configuration without making changes
    
    .OUTPUTS
    Boolean indicating success
    #>

    param(
        [switch]${test-only}
    )
    
    try {
        Write-Info "Configuring Docker Desktop for WSL integration..."
        
        if (${test-only}) {
            Write-Info "Would configure Docker Desktop WSL integration settings"
            return $true
        }
        
        # Docker Desktop settings are stored in %APPDATA%\Docker\settings.json
        $dockerSettingsPath = Join-Path $env:APPDATA "Docker\settings.json"
        
        if (-not (Test-Path $dockerSettingsPath)) {
            Write-Warning "Docker Desktop settings file not found. Docker may need to be started first."
            Write-Info "WSL integration can be configured manually in Docker Desktop settings:"
            Write-Info " 1. Open Docker Desktop"
            Write-Info " 2. Go to Settings -> General -> 'Use the WSL 2 based engine'"
            Write-Info " 3. Go to Settings -> Resources -> WSL integration -> 'Enable integration with my default WSL distro'"
            return $false
        }
        
        try {
            # Read current settings
            $settingsContent = Get-Content $dockerSettingsPath -Raw | ConvertFrom-Json
            $settingsModified = $false
            
            # Enable WSL 2 based engine
            if (-not $settingsContent.PSObject.Properties['useWsl2'] -or -not $settingsContent.useWsl2) {
                Write-Info "Enabling WSL 2 based engine..."
                $settingsContent | Add-Member -Name "useWsl2" -Value $true -MemberType NoteProperty -Force
                $settingsModified = $true
            } else {
                Write-Info "WSL 2 based engine already enabled"
            }
            
            # Enable default WSL distro integration
            if (-not $settingsContent.PSObject.Properties['wslEngineEnabled'] -or -not $settingsContent.wslEngineEnabled) {
                Write-Info "Enabling WSL engine integration..."
                $settingsContent | Add-Member -Name "wslEngineEnabled" -Value $true -MemberType NoteProperty -Force
                $settingsModified = $true
            } else {
                Write-Info "WSL engine integration already enabled"
            }
            
            # Ensure WSL distros integration object exists
            if (-not $settingsContent.PSObject.Properties['enableIntegrationWithDefaultWslDistro'] -or -not $settingsContent.enableIntegrationWithDefaultWslDistro) {
                Write-Info "Enabling integration with default WSL distro..."
                $settingsContent | Add-Member -Name "enableIntegrationWithDefaultWslDistro" -Value $true -MemberType NoteProperty -Force
                $settingsModified = $true
            } else {
                Write-Info "Default WSL distro integration already enabled"
            }
            
            # Save settings if modified
            if ($settingsModified) {
                Write-Progress "Updating Docker Desktop settings..."
                $settingsContent | ConvertTo-Json -Depth 10 | Set-Content $dockerSettingsPath -Encoding UTF8
                Write-Success "Docker Desktop WSL integration settings updated"
                Write-Info "Note: Docker Desktop may need to be restarted for settings to take effect"
            } else {
                Write-Success "Docker Desktop WSL integration already configured"
            }
            
            return $true
            
        } catch {
            Write-Warning "Failed to update Docker settings file: $($_.Exception.Message)"
            Write-Info "Please configure WSL integration manually in Docker Desktop:"
            Write-Info " 1. Open Docker Desktop"
            Write-Info " 2. Go to Settings -> General -> 'Use the WSL 2 based engine'"
            Write-Info " 3. Go to Settings -> Resources -> WSL integration -> 'Enable integration with my default WSL distro'"
            return $false
        }
        
    } catch {
        Write-Warning "Docker WSL integration configuration failed: $($_.Exception.Message)"
        return $false
    }
}

function Install-Docker {
    param(
        [switch]${test-only},
        [switch]$AutoStart,
        [switch]$RequiresWSL,
        [switch]${what-if}
    )
    
    # If test-only mode, just test current installation
    if (${test-only}) {
        return Test-Docker -AutoStart:$AutoStart
    }
    
    # If what-if mode, show what would be done
    if (${what-if}) {
        Write-Host "what if: Would test if Docker is already installed" -ForegroundColor Yellow
        if ($AutoStart) {
            Write-Host "what if: Would start Docker Desktop if daemon is not running" -ForegroundColor Yellow
        }
        if ($RequiresWSL) {
            Write-Host "what if: Would configure Docker for WSL integration" -ForegroundColor Yellow
        }
        Write-Host "what if: Would download Docker Desktop installer if not present" -ForegroundColor Yellow
        Write-Host "what if: Would install Docker Desktop with silent installation" -ForegroundColor Yellow
        Write-Host "what if: Would verify Docker installation and daemon connectivity" -ForegroundColor Yellow
        return $true
    }
    
    Write-Step "Installing Docker Desktop..."
    
    try {
        # Check if Docker is already installed
        if (Test-Command "docker") {
            $dockerVersion = docker --version 2>$null
            if ($dockerVersion) {
                Write-Success "Docker is already installed: $dockerVersion"
                
                # Try to start Docker Desktop if AutoStart is enabled and daemon is not running
                $dockerInfo = docker info 2>$null
                if ($LASTEXITCODE -ne 0 -and $AutoStart) {
                    Write-Info "Docker daemon is not running. Attempting to start Docker Desktop..."
                    try {
                        $dockerDesktopPath = "C:\Program Files\Docker\Docker\Docker Desktop.exe"
                        if (Test-Path $dockerDesktopPath) {
                            Start-Process $dockerDesktopPath -WindowStyle Hidden
                            Write-Info "Docker Desktop startup initiated. This may take a few minutes..."
                            Write-Info "Please wait for Docker Desktop to fully start before using Docker commands."
                        } else {
                            Write-Warning "Docker Desktop executable not found at expected location"
                        }
                    } catch {
                        Write-Warning "Failed to start Docker Desktop: $($_.Exception.Message)"
                    }
                }
                
                # Configure WSL integration if required
                if ($RequiresWSL) {
                    Write-Info "Configuring Docker for WSL integration..."
                    $wslIntegrationResult = Set-DockerWSLIntegration -test-only:${test-only}
                    if ($wslIntegrationResult) {
                        Write-Success "Docker WSL integration configured"
                    } else {
                        Write-Warning "Docker WSL integration configuration failed - may need manual setup"
                    }
                }
                
                return $true
            }
        }
        
        $installChoice = Read-UserPrompt -Prompt "Docker not found. Install Docker Desktop?" -ValidValues @("y","n")
        if (-not (Test-YesResponse $installChoice)) {
            Write-Warning "Skipping Docker installation"
            return $false
        }
        
        Write-Progress "Installing Docker Desktop..."
        
        # Try different installation methods
        $installSuccess = $false
        
        # Method 1: Try winget (Windows Package Manager)
        if (Test-Command "winget") {
            try {
                Write-Info "Installing Docker Desktop via winget..."
                $result = winget install Docker.DockerDesktop --accept-package-agreements --accept-source-agreements --silent
                if ($LASTEXITCODE -eq 0) {
                    $installSuccess = $true
                    Write-Success "Docker Desktop installed via winget"
                }
            } catch {
                Write-Warning "winget installation failed: $($_.Exception.Message)"
            }
        }
        
        # Method 2: Try chocolatey if winget failed
        if (-not $installSuccess -and (Test-Command "choco")) {
            try {
                Write-Info "Installing Docker Desktop via chocolatey..."
                choco install docker-desktop -y
                if ($LASTEXITCODE -eq 0) {
                    $installSuccess = $true
                    Write-Success "Docker Desktop installed via chocolatey"
                }
            } catch {
                Write-Warning "Chocolatey installation failed: $($_.Exception.Message)"
            }
        }
        
        # Method 3: Direct download if package managers failed
        if (-not $installSuccess) {
            try {
                Write-Info "Downloading Docker Desktop installer..."
                $dockerUrl = "https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe"
                $installerPath = Join-Path $env:TEMP "DockerDesktopInstaller.exe"
                
                # Download with progress
                $webClient = New-Object System.Net.WebClient
                $webClient.DownloadFile($dockerUrl, $installerPath)
                
                Write-Info "Running Docker Desktop installer..."
                $installArgs = @("install", "--quiet", "--accept-license")
                $process = Start-Process -FilePath $installerPath -ArgumentList $installArgs -Wait -PassThru
                
                if ($process.ExitCode -eq 0) {
                    $installSuccess = $true
                    Write-Success "Docker Desktop installed via direct download"
                } else {
                    Write-Warning "Docker installer returned exit code: $($process.ExitCode)"
                }
                
                # Cleanup
                if (Test-Path $installerPath) {
                    Remove-Item $installerPath -Force
                }
            } catch {
                Write-Warning "Direct download installation failed: $($_.Exception.Message)"
            }
        }
        
        if ($installSuccess) {
            Write-Info "Docker Desktop has been installed. You may need to restart your computer."
            Write-Info "After restart, Docker Desktop will need to be started manually."
            
            # Add Docker to PATH if needed
            $dockerPath = "${env:ProgramFiles}\Docker\Docker\resources\bin"
            if (Test-Path $dockerPath) {
                $currentPath = [Environment]::GetEnvironmentVariable("PATH", "Machine")
                if ($currentPath -notlike "*$dockerPath*") {
                    [Environment]::SetEnvironmentVariable("PATH", "$currentPath;$dockerPath", "Machine")
                    Write-Info "Added Docker to system PATH"
                }
            }
            
            Write-Success "Docker installation completed"
            
            # Configure WSL integration if required
            if ($RequiresWSL) {
                Write-Info "Configuring Docker for WSL integration..."
                $wslIntegrationResult = Set-DockerWSLIntegration -test-only:${test-only}
                if ($wslIntegrationResult) {
                    Write-Success "Docker WSL integration configured"
                } else {
                    Write-Warning "Docker WSL integration configuration failed - may need manual setup"
                }
            }
            
            return $true
        } else {
            Write-Error "Failed to install Docker Desktop"
            Write-Info "Please install Docker Desktop manually from: https://docs.docker.com/desktop/install/windows-install/"
            return $false
        }
        
    } catch {
        Write-Error "Docker installation failed: $($_.Exception.Message)"
        return $false
    }
}

# Main execution
if ($MyInvocation.InvocationName -ne '.') {
    $result = Install-Docker -test-only:${test-only} -AutoStart:$AutoStart -RequiresWSL:$RequiresWSL -what-if:${what-if}
    
    if ($result) {
        if (${test-only}) {
            Write-Success "Docker test completed successfully"
        } else {
            Write-Success "Docker installation completed successfully"
        }
        exit 0
    } else {
        if (${test-only}) {
            Write-Error "Docker test failed"
        } else {
            Write-Error "Docker installation failed"
        }
        exit 1
    }
}

# Export functions for module usage
if ($MyInvocation.MyCommand.ModuleName) {
    Export-ModuleMember -Function @(
        'Install-Docker'
    )
}