#////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: <ProjectRoot>/Launch-Borealis.ps1

<#
    Borealis.ps1
    ----------------------
    This script deploys the Borealis Workflow Automation Tool with three modules:
      - Server (Web Dashboard)
      - Agent (Client / Data Collector)
      - Desktop App (Electron)

    It begins by presenting a menu to the user. Based on the selection,
    the corresponding module is launched or deployed.

    Usage:
      Set-ExecutionPolicy Unrestricted -Scope Process; .\Borealis.ps1
#>

Clear-Host

# ASCII Art Banner
@'

███████████                                        ████   ███         
░░███░░░░░███                                      ░░███  ░░░          
 ░███    ░███  ██████  ████████   ██████   ██████   ░███  ████   █████ 
 ░██████████  ███░░███░░███░░███ ███░░███ ░░░░░███  ░███ ░░███  ███░░  
 ░███░░░░░███░███ ░███ ░███ ░░░ ░███████   ███████  ░███  ░███ ░░█████ 
 ░███    ░███░███ ░███ ░███     ░███░░░   ███░░███  ░███  ░███  ░░░░███
 ███████████ ░░██████  █████    ░░██████ ░░████████ █████ █████ ██████ 
░░░░░░░░░░░   ░░░░░░  ░░░░░      ░░░░░░   ░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░  
'@ | Write-Host -ForegroundColor DarkCyan
Write-Host "Drag-&-Drop Automation Orchestration | Macros | Data Collection & Analysis" -ForegroundColor DarkGray
Write-Host " "
Write-Host "Ensuring Dependencies Exist..." -ForegroundColor DarkCyan
# ---------------------- ASCII Art Terminal Required Changes ----------------------
# Set the .NET Console output encoding to UTF8
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

# Change the Windows OEM code page to 65001 (UTF-8)
chcp.com 65001 > $null

# ---------------------- Add Common Functions Used Throughout Script ----------------------
$symbols = @{
    Success = [char]0x2705
    Running = [char]0x23F3
    Fail    = [char]0x274C
    Info    = [char]0x2139
}

function Write-ProgressStep {
    param (
        [string]$Message,
        [string]$Status = $symbols["Info"]
    )
    Write-Host "`r$Status $Message... " -NoNewline
}

function Run-Step {
    param (
        [string]     $Message,
        [scriptblock]$Script
    )
    Write-ProgressStep -Message $Message -Status "$($symbols.Running)"
    try {
        & $Script
        if ($LASTEXITCODE -eq 0 -or $?) {
            Write-Host "`r$($symbols.Success) $Message                        "
        } else {
            throw "Non-zero exit code"
        }
    } catch {
        Write-Host "`r$($symbols.Fail) $Message - Failed: $_                        " -ForegroundColor Red
        exit 1
    }
}

# ---------------------- Server Deployment / Operation Mode Variables ----------------------
# Define the default operation mode: production  | developer
[string]$borealis_operation_mode = 'production'

# ---------------------- Bundle Executables Setup ----------------------
$scriptDir  = Split-Path $MyInvocation.MyCommand.Path -Parent
$depsRoot   = Join-Path $scriptDir 'Dependencies'
$pythonExe  = Join-Path $depsRoot 'Python\python.exe'
$nodeExe    = Join-Path $depsRoot 'NodeJS\node.exe'
$sevenZipExe    = Join-Path $depsRoot "7zip\7z.exe"
$npmCmd     = Join-Path (Split-Path $nodeExe) 'npm.cmd'
$npxCmd     = Join-Path (Split-Path $nodeExe) 'npx.cmd'
$node7zUrl      = "https://nodejs.org/dist/v23.11.0/node-v23.11.0-win-x64.7z"
$nodeInstallDir = Join-Path $depsRoot "NodeJS"
$node7zPath     = Join-Path $depsRoot "node-v23.11.0-win-x64.7z"

# ---------------------- Ensure NodeJS is Present (Bundled via 7-Zip) ----------------------
Run-Step "Dependency: NodeJS" {
    if (-not (Test-Path $nodeExe)) {
        # Download archive if not present
        if (-not (Test-Path $node7zPath)) {
            Invoke-WebRequest -Uri $node7zUrl -OutFile $node7zPath
        }

        # Extract using bundled 7z
        if (-not (Test-Path $sevenZipExe)) {
            throw "7-Zip CLI not found at: $sevenZipExe"
        }

        & $sevenZipExe x $node7zPath "-o$nodeInstallDir" -y | Out-Null

        # The extracted contents might live under a subfolder; flatten if needed
        $extracted = Get-ChildItem $nodeInstallDir | Where-Object { $_.PSIsContainer } | Select-Object -First 1
        if ($extracted) {
            Get-ChildItem $extracted.FullName | Move-Item -Destination $nodeInstallDir -Force
            Remove-Item $extracted.FullName -Recurse -Force
        }

        # Clean Up 7z File After Extraction
        Remove-Item -Recurse -Force -ErrorAction SilentlyContinue $node7zPath
    }
}

# ---------------------- Ensure Python is Present (via Installer Extraction) ----------------------
Run-Step "Dependency: Python" {
    $pythonInstallDir = Join-Path $scriptDir "Dependencies\Python"
    $pythonExe = Join-Path $pythonInstallDir "python.exe"

    $pythonMsiBaseUrl = "https://www.python.org/ftp/python/3.13.3/amd64/"
    $pythonMsiFiles = @(
        "core.msi",
        "exe.msi",
        "lib.msi",
        "pip.msi",
        "dev.msi"
    )

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

        foreach ($file in $pythonMsiFiles) {
            $url = "$pythonMsiBaseUrl$file"
            $localPath = Join-Path $scriptDir "Dependencies\$file"

            # Download if missing
            if (-not (Test-Path $localPath)) {
                Invoke-WebRequest -Uri $url -OutFile $localPath
            }

            # Extract MSI into install directory
            Start-Process -Wait -NoNewWindow -FilePath "msiexec.exe" `
                -ArgumentList "/a `"$localPath`" /qn TARGETDIR=`"$pythonInstallDir`""
        }

        # Clean up downloaded MSIs
        foreach ($file in $pythonMsiFiles) {
            $localPath = Join-Path $scriptDir "Dependencies\$file"
            Remove-Item $localPath -Force -ErrorAction SilentlyContinue
        }

        # Validate success
        if (-not (Test-Path $pythonExe)) {
            throw "Python executable not found after MSI extraction."
        }
    } else {
    }
}

# ---------------------- Ensure Tesseract OCR is Present (Extract from SFX EXE) ----------------------
Run-Step "Dependency: Tesseract-OCR" {
    $tessExeUrl     = "https://github.com/tesseract-ocr/tesseract/releases/download/5.5.0/tesseract-ocr-w64-setup-5.5.0.20241111.exe"
    $tessExePath    = Join-Path $depsRoot "tesseract-installer.exe"
    $tessInstallDir = Join-Path $scriptDir "Data\Server\Python_API_Endpoints\Tesseract-OCR"

    if (-not (Test-Path (Join-Path $tessInstallDir "tesseract.exe"))) {
        # Download the installer if it doesn't exist
        if (-not (Test-Path $tessExePath)) {
            Invoke-WebRequest -Uri $tessExeUrl -OutFile $tessExePath
        }

        # Extract using 7-Zip
        if (-not (Test-Path $sevenZipExe)) {
            throw "7-Zip CLI not found at: $sevenZipExe"
        }

        if (Test-Path $tessInstallDir) {
            Remove-Item $tessInstallDir -Recurse -Force -ErrorAction SilentlyContinue
        }
        New-Item -ItemType Directory -Path $tessInstallDir | Out-Null

        & $sevenZipExe x $tessExePath "-o$tessInstallDir" -y | Out-Null

        # Optional cleanup
        Remove-Item $tessExePath -Force -ErrorAction SilentlyContinue
    }
}

# ---------------------- Download Tesseract English Language Trained Data ----------------------
Run-Step "Dependency: Tesseract-OCR - Trained Model Data" {
    $langDataDir = Join-Path $scriptDir "Data\Server\Python_API_Endpoints\Tesseract-OCR\tessdata"
    $engPath     = Join-Path $langDataDir "eng.traineddata"
    $osdPath     = Join-Path $langDataDir "osd.traineddata"

    if (-not (Test-Path $engPath)) {
        Invoke-WebRequest -Uri "https://github.com/tesseract-ocr/tessdata/raw/main/eng.traineddata" -OutFile $engPath
    }

    if (-not (Test-Path $osdPath)) {
        Invoke-WebRequest -Uri "https://github.com/tesseract-ocr/tessdata/raw/main/osd.traineddata" -OutFile $osdPath
    }
}

# ---------------------- Common Initialization & Visuals ----------------------
Clear-Host

# ASCII Art Banner
@'

███████████                                        ████   ███         
░░███░░░░░███                                      ░░███  ░░░          
 ░███    ░███  ██████  ████████   ██████   ██████   ░███  ████   █████ 
 ░██████████  ███░░███░░███░░███ ███░░███ ░░░░░███  ░███ ░░███  ███░░  
 ░███░░░░░███░███ ░███ ░███ ░░░ ░███████   ███████  ░███  ░███ ░░█████ 
 ░███    ░███░███ ░███ ░███     ░███░░░   ███░░███  ░███  ░███  ░░░░███
 ███████████ ░░██████  █████    ░░██████ ░░████████ █████ █████ ██████ 
░░░░░░░░░░░   ░░░░░░  ░░░░░      ░░░░░░   ░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░  
'@ | Write-Host -ForegroundColor DarkCyan
Write-Host "Drag-&-Drop Automation Orchestration | Macros | Data Collection & Analysis" -ForegroundColor DarkGray

foreach ($tool in @($pythonExe, $nodeExe, $npmCmd, $npxCmd)) {
    if (-not (Test-Path $tool)) {
        Write-Host "`r$($symbols.Fail) Bundled executable not found at '$tool'." -ForegroundColor Red
        exit 1
    }
}

$env:PATH = '{0};{1};{2}' -f (Split-Path $pythonExe), (Split-Path $nodeExe), $env:PATH

# ---------------------- Menu Prompt & User Input ----------------------
Write-Host " "
Write-Host "Please choose which function you want to launch:"
Write-Host " 1) Borealis Server" -ForegroundColor DarkGray
Write-Host " 2) Borealis Agent" -ForegroundColor DarkGray
Write-Host " 3) Build Electron App " -NoNewline -ForegroundColor DarkGray
Write-Host "[Experimental]" -ForegroundColor Red
Write-Host " 4) Package Self-Contained EXE of Server or Agent " -NoNewline -ForegroundColor DarkGray
Write-Host "[Experimental]" -ForegroundColor Red
Write-Host " 5) Update Borealis " -NoNewLine -ForegroundColor DarkGray
Write-Host "[Requires Re-Build]" -ForegroundColor Red
Write-Host "Type a number and press " -NoNewLine
Write-Host "<ENTER>" -ForegroundColor DarkCyan
$choice = Read-Host
switch ($choice) {

    "1" {
        Write-Host " "
        Write-Host "Configure Borealis Server Mode:" -ForegroundColor DarkYellow
        Write-Host " 1) Build & Launch > " -NoNewLine -ForegroundColor DarkGray
        Write-Host "Production Flask Server @ " -NoNewLine
        Write-Host "http://localhost:5000" -ForegroundColor DarkCyan
        Write-Host " 2) [Skip Build] & Immediately Launch > " -NoNewLine -ForegroundColor DarkGray
        Write-Host "Production Flask Server @ " -NoNewLine
        Write-Host "http://localhost:5000" -ForegroundColor DarkCyan
        Write-Host " 3) Launch > " -NoNewLine -ForegroundColor DarkGray
        Write-Host "[Hotload-Ready] " -NoNewLine -ForegroundColor Green
        Write-Host "Vite Dev Server @ " -NoNewLine
        Write-Host "http://localhost:5173" -ForegroundColor DarkCyan
        $modeChoice = Read-Host "Enter choice [1/2/3]"

        switch ($modeChoice) {
            "1" { $borealis_operation_mode = "production" }
            "2" {
                Run-Step "Borealis: Launch Flask Server" {
                    Push-Location (Join-Path $scriptDir "Server")
                    & (Join-Path $scriptDir "Server\Scripts\python.exe") (Join-Path $scriptDir "Server\Borealis\server.py")
                    Pop-Location
                }
                Exit 0
            }
            "3" { $borealis_operation_mode = "developer"  }
            default {
                Write-Host "Invalid mode choice: $modeChoice" -ForegroundColor Red
                Exit 1
            }
        }

        # ───── Now run your deploy logic ─────
        Write-Host "Deploying Borealis Server in '$borealis_operation_mode' mode" -ForegroundColor Blue

        $venvFolder       = "Server"
        $dataSource       = "Data"
        $dataDestination  = "$venvFolder\Borealis"
        $customUIPath     = "$dataSource\Server\WebUI"
        $webUIDestination = "$venvFolder\web-interface"
        $venvPython       = Join-Path $venvFolder 'Scripts\python.exe'

        # Create Virtual Environment & Copy Server Assets
        Run-Step "Create Borealis Virtual Python Environment" {
            # Leverage Bundled Python Dependency to Construct Virtual Python Environment
            if (-not (Test-Path "$venvFolder\Scripts\Activate")) { & $pythonExe -m venv $venvFolder | Out-Null }
            if (Test-Path $dataSource) {
                Remove-Item $dataDestination -Recurse -Force -ErrorAction SilentlyContinue
                New-Item -Path $dataDestination -ItemType Directory -Force | Out-Null
                Copy-Item "$dataSource\Server\Python_API_Endpoints" $dataDestination -Recurse
                Copy-Item "$dataSource\Server\Sounds"                 $dataDestination -Recurse
                Copy-Item "$dataSource\Server\server.py"              $dataDestination
            }
            . "$venvFolder\Scripts\Activate"
        }

        # Install Python Dependencies
        Run-Step "Install Python Dependencies into Virtual Python Environment" {
            if (Test-Path "$dataSource\Server\server-requirements.txt") {
                & $venvPython -m pip install --disable-pip-version-check -q -r "$dataSource\Server\server-requirements.txt" | Out-Null
            }
        }

        # Copy Vite WebUI Assets
        Run-Step "Copy Borealis WebUI Files into: $webUIDestination" {
            if (Test-Path $webUIDestination) {
                Remove-Item "$webUIDestination\public\*" -Recurse -Force -ErrorAction SilentlyContinue
                Remove-Item "$webUIDestination\src\*"    -Recurse -Force -ErrorAction SilentlyContinue
            } else {
                New-Item -Path $webUIDestination -ItemType Directory -Force | Out-Null
            }
            Copy-Item "$customUIPath\*" $webUIDestination -Recurse -Force
        }

        # NPM Install for WebUI
        Run-Step "Vite Web Frontend: Install NPM Packages" {
            Push-Location $webUIDestination
            $env:npm_config_loglevel = "silent"
            & $npmCmd install --silent --no-fund --audit=false | Out-Null
            Pop-Location
        }

        # Vite Operation Mode Control (build vs dev)
        Run-Step "Vite Web Frontend: Start ($borealis_operation_mode)" {
            Push-Location $webUIDestination
            if ($borealis_operation_mode -eq "developer") { $viteSubCommand = "dev" } else { $viteSubCommand = "build" }
            Start-Process -NoNewWindow -FilePath $npmCmd -ArgumentList @("run",$viteSubCommand)
            Pop-Location
        }

        # Launch Flask Server
        Run-Step "Borealis: Launch Flask Server" {
            Push-Location (Join-Path $scriptDir "Server")
            $py        = Join-Path $scriptDir "Server\Scripts\python.exe"
            $server_py = Join-Path $scriptDir "Server\Borealis\server.py"

            Write-Host "`nLaunching Borealis..." -ForegroundColor Green
            Write-Host "===================================================================================="
            Write-Host "$($symbols.Running) Python Flask API Server Started..."

            & $py $server_py
            Pop-Location
        }
        break
    }

    "2" {
        # Agent Deployment (Client / Data Collector)
        Write-Host " "
        Write-Host "Deploying Borealis Agent..." -ForegroundColor Blue
        
        $venvFolder             = "Agent"
        $agentSourcePath        = "Data\Agent\borealis-agent.py"
        $agentRequirements      = "Data\Agent\agent-requirements.txt"
        $agentDestinationFolder = "$venvFolder\Borealis"
        $agentDestinationFile   = "$venvFolder\Borealis\borealis-agent.py"
        $venvPython = Join-Path $scriptDir $venvFolder | Join-Path -ChildPath 'Scripts\python.exe'

        Run-Step "Create Virtual Python Environment" {
            if (-not (Test-Path "$venvFolder\Scripts\Activate")) {
                & $pythonExe -m venv $venvFolder
            }
            if (Test-Path $agentSourcePath) {
                Remove-Item $agentDestinationFolder -Recurse -Force -ErrorAction SilentlyContinue
                New-Item -Path $agentDestinationFolder -ItemType Directory -Force | Out-Null
                Copy-Item $agentSourcePath $agentDestinationFile -Force
            }
            . "$venvFolder\Scripts\Activate"
        }

        Run-Step "Install Python Dependencies" {
            if (Test-Path $agentRequirements) {
                & $venvPython -m pip install --disable-pip-version-check -q -r $agentRequirements | Out-Null
            }
        }

        Write-Host "`nLaunching Borealis Agent..." -ForegroundColor Blue
        Write-Host "===================================================================================="
        & $venvPython -W ignore::SyntaxWarning $agentDestinationFile
    }

    "3" {
        # Desktop App Deployment (Electron)
        Clear-Host
        Write-Host "Deploying Borealis Desktop App..." -ForegroundColor Cyan
        Write-Host "===================================================================================="
        
        $electronSource      = "Data\Electron"
        $electronDestination = "ElectronApp"
        $scriptDir           = Split-Path $MyInvocation.MyCommand.Path -Parent

        # 1) Prepare ElectronApp folder
        Run-Step "Prepare ElectronApp folder" {
            if (Test-Path $electronDestination) {
                Remove-Item $electronDestination -Recurse -Force
            }
            New-Item -Path $electronDestination -ItemType Directory | Out-Null

            # Copy deployed Flask server
            $deployedServer = Join-Path $scriptDir 'Server\Borealis'
            if (-not (Test-Path $deployedServer)) {
                throw "Server\Borealis not found - please run choice 1 first."
            }
            Copy-Item $deployedServer "$electronDestination\Server" -Recurse

            # Copy Electron scaffold files
            Copy-Item "$electronSource\package.json" "$electronDestination" -Force
            Copy-Item "$electronSource\main.js"        "$electronDestination" -Force

            # Copy built WebUI into renderer
            $staticBuild = Join-Path $scriptDir 'Server\web-interface\build'
            if (-not (Test-Path $staticBuild)) {
                throw "WebUI build not found - run choice 1 to build WebUI first."
            }
            Copy-Item "$staticBuild\*" "$electronDestination\renderer" -Recurse -Force
        }

        # 2) Install Electron & Builder
        Run-Step "ElectronApp: Install Node dependencies" {
            Push-Location $electronDestination
            $env:NODE_ENV = ''
            $env:npm_config_production = ''
            & $npmCmd install --silent --no-fund --audit=false
            Pop-Location
        }

        # 3) Package desktop app
        Run-Step "ElectronApp: Package with electron-builder" {
            Push-Location $electronDestination
            & $npmCmd run dist
            Pop-Location
        }

        # 4) Launch in dev mode
        Run-Step "ElectronApp: Launch in dev mode" {
            Push-Location $electronDestination
            & $npmCmd run dev
            Pop-Location
        }
    }

    "4" {
        # Prompt the User for Which System to Package using Pyinstaller
        Write-Host "Choose which module to package into a self-contained EXE file:" -ForegroundColor DarkYellow
        Write-Host " 1) Server" -ForegroundColor DarkGray
        Write-Host " 2) Agent" -ForegroundColor DarkGray
        $exePackageChoice = Read-Host "Enter choice [1/2]"

        switch ($exePackageChoice) {
            "1" { 
                $serverScriptDir = Join-Path -Path $PSScriptRoot -ChildPath "Data\Server"
                Set-Location -Path $serverScriptDir
                & (Join-Path -Path $serverScriptDir -ChildPath "Package-Borealis-Server.ps1") 
            }
        
            "2" { 
                $agentScriptDir = Join-Path -Path $PSScriptRoot -ChildPath "Data\Agent"
                Set-Location -Path $agentScriptDir
                & (Join-Path -Path $agentScriptDir -ChildPath "Package_Borealis-Agent.ps1") 
            }
        
            default {
                Write-Host "Invalid Choice. Exiting..." -ForegroundColor Red
                exit 1
            }
        }        
    }

    default {
        Write-Host "Invalid selection. Exiting..." -ForegroundColor Red
        exit 1
    }

    "5" {
        Write-Host " "
        Write-Host "Updating Borealis..." -ForegroundColor Green

        # Prepare paths
        $updateZip = Join-Path $scriptDir "Update_Staging\main.zip"
        $updateDir = Join-Path $scriptDir "Update_Staging\borealis"
        $preservePath = Join-Path $scriptDir "Data\Server\Python_API_Endpoints\Tesseract-OCR"
        $preserveBackupPath = Join-Path $scriptDir "Update_Staging\Tesseract-OCR"

        Run-Step "Updating: Move Tesseract-OCR Folder Somewhere Safe to Restore Later" {
            if (Test-Path $preservePath) {
                # Ensure staging folder exists
                $stagingPath = Join-Path $scriptDir "Update_Staging"
                if (-not (Test-Path $stagingPath)) {
                    New-Item -ItemType Directory -Force -Path $stagingPath | Out-Null
                }

                Move-Item -Path $preservePath -Destination $preserveBackupPath -Force
            }
        }

        Run-Step "Updating: Clean Up Folders to Prepare for Update" {
            Remove-Item -Recurse -Force -ErrorAction SilentlyContinue `
            (Join-Path $scriptDir "Data"), `
            (Join-Path $scriptDir "Server\web-interface\src"), `
            (Join-Path $scriptDir "Server\web-interface\build"), `
            (Join-Path $scriptDir "Server\web-interface\public"), `
            (Join-Path $scriptDir "Server\Borealis")
        }

        Run-Step "Updating: Create Update Staging Folder" {
            $stagingPath = Join-Path $scriptDir "Update_Staging"
            if (-not (Test-Path $stagingPath)) {
                New-Item -ItemType Directory -Force -Path $stagingPath | Out-Null
            }

            $updateZip = Join-Path $stagingPath "main.zip"
            $updateDir = Join-Path $stagingPath "borealis"
        }

        Run-Step "Updating: Download Update from https://git.bunny-lab.io/bunny-lab/Borealis/archive/main.zip" {
            Invoke-WebRequest -Uri "https://git.bunny-lab.io/bunny-lab/Borealis/archive/main.zip" -OutFile $updateZip
        }

        Run-Step "Updating: Extract Update Files" {
            Expand-Archive -Path $updateZip -DestinationPath (Join-Path $scriptDir "Update_Staging") -Force
        }

        Run-Step "Updating: Copy Update Files into Production Borealis Root Folder" {
            Copy-Item "$updateDir\*" $scriptDir -Recurse -Force
        }

        Run-Step "Updating: Restore Tesseract-OCR Folder" {
            $restorePath = Join-Path $scriptDir "Data\Server\Python_API_Endpoints"
            if (Test-Path $preserveBackupPath) {
                # Ensure destination path exists
                if (-not (Test-Path $restorePath)) {
                    New-Item -ItemType Directory -Force -Path $restorePath | Out-Null
                }

                Move-Item -Path $preserveBackupPath -Destination $restorePath -Force
            }
        }

        Run-Step "Updating: Clean Up Update Staging Folder" {
            Remove-Item -Recurse -Force -ErrorAction SilentlyContinue (Join-Path $scriptDir "Update_Staging")
        }

        Write-Host "`nUpdate Complete! Please Re-Launch the Borealis Script." -ForegroundColor Green
        Read-Host "Press any key to re-launch Borealis..."
        & (Join-Path $scriptDir "Borealis.ps1")
        Exit 0
    }
}