<#
.SYNOPSIS
    ROA2WEB - Auto-Deploy Monitor (Server-Side) - Ultrathin Monolith

.DESCRIPTION
    Server-side script that monitors C:\Temp\ for new deployment packages
    and automatically deploys them using ROA2WEB-Console.ps1.

    Designed for ULTRATHIN MONOLITH architecture:
    - Single unified backend service (ROA2WEB-Backend)
    - All modules deployed together (Reports, Data Entry, Telegram)
    - Automatic detection and deployment

    Can run:
    - Via Scheduled Task (automated, silent)
    - Interactive mode (manual execution with menu)
    - Non-interactive mode (command-line automation)

.PARAMETER Interactive
    Run in interactive mode with menu

.PARAMETER WatchPath
    Path to monitor for deployment packages (default: C:\Temp)

.PARAMETER StateFile
    Path to state file tracking last deployment (default: C:\Temp\ROA2WEB-Scripts\last-deploy.json)

.PARAMETER ConsoleScriptPath
    Path to ROA2WEB-Console.ps1 script

.PARAMETER LogPath
    Path to log file directory (default: C:\Temp\ROA2WEB-Scripts\Logs)

.PARAMETER CheckOnly
    Check for updates without deploying

.EXAMPLE
    .\Check-And-Deploy.ps1
    Check for new packages and deploy automatically (silent)

.EXAMPLE
    .\Check-And-Deploy.ps1 -Interactive
    Show interactive menu with deployment options

.EXAMPLE
    .\Check-And-Deploy.ps1 -CheckOnly
    Check for new packages without deploying

.NOTES
    Author: ROA2WEB Team
    Version: 1.0 (Auto-Deploy Monitor)
    Requires: Administrator privileges, PowerShell 5.1+

    Designed to run via Scheduled Task for automated deployments.
#>

[CmdletBinding()]
param(
    [switch]$Interactive,
    [string]$WatchPath = "C:\Temp",
    [string]$StateFile = "C:\Temp\ROA2WEB-Scripts\last-deploy.json",
    [string]$ConsoleScriptPath = "",
    [string]$LogPath = "C:\Temp\ROA2WEB-Scripts\Logs",
    [switch]$CheckOnly
)

$ErrorActionPreference = "Stop"

# =============================================================================
# CONFIGURATION
# =============================================================================

$script:Config = @{
    WatchPath = $WatchPath
    StateFile = $StateFile
    LogPath = $LogPath
    ConsoleScriptPath = if ($ConsoleScriptPath) {
        $ConsoleScriptPath
    } else {
        # Auto-detect ROA2WEB-Console.ps1
        $possiblePaths = @(
            "C:\inetpub\wwwroot\roa2web\scripts\ROA2WEB-Console.ps1",
            (Join-Path $PSScriptRoot "ROA2WEB-Console.ps1")
        )
        $found = $possiblePaths | Where-Object { Test-Path $_ } | Select-Object -First 1
        if ($found) { $found } else { "" }
    }
}

# =============================================================================
# HELPER FUNCTIONS
# =============================================================================

function Write-Log {
    param(
        [string]$Message,
        [ValidateSet("INFO", "SUCCESS", "WARNING", "ERROR")]
        [string]$Level = "INFO"
    )

    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "[$timestamp] [$Level] $Message"

    # Ensure log directory exists
    if (-not (Test-Path $script:Config.LogPath)) {
        New-Item -ItemType Directory -Path $script:Config.LogPath -Force | Out-Null
    }

    $logFile = Join-Path $script:Config.LogPath "check-and-deploy.log"
    Add-Content -Path $logFile -Value $logMessage

    # Also write to console if interactive
    if ($Interactive) {
        $color = switch ($Level) {
            "SUCCESS" { "Green" }
            "WARNING" { "Yellow" }
            "ERROR" { "Red" }
            default { "White" }
        }
        Write-Host $logMessage -ForegroundColor $color
    }
}

function Write-Step {
    param([string]$Message)
    Write-Host "`n[*] $Message" -ForegroundColor Cyan
    Write-Log -Message $Message -Level "INFO"
}

function Write-Success {
    param([string]$Message)
    Write-Host "    [OK] $Message" -ForegroundColor Green
    Write-Log -Message $Message -Level "SUCCESS"
}

function Write-Error {
    param([string]$Message)
    Write-Host "    [ERROR] $Message" -ForegroundColor Red
    Write-Log -Message $Message -Level "ERROR"
}

function Write-Warning {
    param([string]$Message)
    Write-Host "    [WARN] $Message" -ForegroundColor Yellow
    Write-Log -Message $Message -Level "WARNING"
}

function Wait-ForKeyPress {
    Write-Host "`nPress any key to continue..." -ForegroundColor Gray
    $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}

# =============================================================================
# STATE MANAGEMENT
# =============================================================================

function Get-DeploymentState {
    if (Test-Path $script:Config.StateFile) {
        try {
            return Get-Content -Path $script:Config.StateFile -Raw | ConvertFrom-Json
        } catch {
            Write-Warning "Failed to load state file, starting fresh"
            return $null
        }
    }
    return $null
}

function Save-DeploymentState {
    param(
        [Parameter(Mandatory)]
        [hashtable]$DeploymentInfo
    )

    try {
        # Load existing state
        $state = Get-DeploymentState

        $newEntry = @{
            packageName = $DeploymentInfo.PackageName
            component = $DeploymentInfo.Component
            timestamp = (Get-Date).ToUniversalTime().ToString("o")
            status = $DeploymentInfo.Status
            services = $DeploymentInfo.Services
        }

        if ($state) {
            # Add current deployment to history
            if (-not $state.history) {
                $state.history = @()
            }
            if ($state.lastDeployment) {
                $state.history = @($state.lastDeployment) + $state.history
            }

            # Keep only last 10 entries in history
            if ($state.history.Count -gt 10) {
                $state.history = $state.history | Select-Object -First 10
            }

            $state.lastDeployment = $newEntry
        } else {
            $state = @{
                lastDeployment = $newEntry
                history = @()
            }
        }

        # Ensure directory exists
        $stateDir = Split-Path $script:Config.StateFile -Parent
        if (-not (Test-Path $stateDir)) {
            New-Item -ItemType Directory -Path $stateDir -Force | Out-Null
        }

        # Save state
        $state | ConvertTo-Json -Depth 10 | Set-Content -Path $script:Config.StateFile
        Write-Success "Deployment state saved"
    } catch {
        Write-Error "Failed to save deployment state: $_"
    }
}

# =============================================================================
# PACKAGE DETECTION
# =============================================================================

function Get-LatestDeploymentPackage {
    Write-Step "Scanning for deployment packages..."

    if (-not (Test-Path $script:Config.WatchPath)) {
        Write-Warning "Watch path does not exist: $($script:Config.WatchPath)"
        return $null
    }

    # Find all deploy-* folders
    $packages = Get-ChildItem -Path $script:Config.WatchPath -Directory |
                Where-Object { $_.Name -match "^deploy-\d{8}-\d{6}$" } |
                Sort-Object LastWriteTime -Descending

    if ($packages.Count -eq 0) {
        Write-Warning "No deployment packages found"
        return $null
    }

    $latest = $packages | Select-Object -First 1
    Write-Success "Found $($packages.Count) package(s), latest: $($latest.Name)"

    return $latest
}

function Test-IsNewPackage {
    param([Parameter(Mandatory)]$Package)

    $state = Get-DeploymentState

    if (-not $state -or -not $state.lastDeployment) {
        Write-Success "No previous deployment found - this is a new package"
        return $true
    }

    $lastDeployed = $state.lastDeployment.packageName

    if ($Package.Name -ne $lastDeployed) {
        Write-Success "New package detected (last deployed: $lastDeployed)"
        return $true
    }

    Write-Log -Message "Package already deployed: $($Package.Name)" -Level "INFO"
    return $false
}

# =============================================================================
# DEPLOYMENT EXECUTION
# =============================================================================

function Invoke-Deployment {
    param([Parameter(Mandatory)]$Package)

    Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
    Write-Host "  STARTING DEPLOYMENT" -ForegroundColor Cyan
    Write-Host ("=" * 70) -ForegroundColor Cyan
    Write-Host "`nPackage: $($Package.Name)" -ForegroundColor Yellow
    Write-Host "Path: $($Package.FullName)" -ForegroundColor Gray

    # Find ROA2WEB-Console.ps1 in package
    $consoleScript = Join-Path $Package.FullName "scripts\ROA2WEB-Console.ps1"

    if (-not (Test-Path $consoleScript)) {
        Write-Error "ROA2WEB-Console.ps1 not found in package: $consoleScript"
        return $false
    }

    try {
        Write-Step "Executing deployment via ROA2WEB-Console.ps1..."

        # Execute deployment (deploy all components)
        Push-Location (Split-Path $consoleScript -Parent)

        & $consoleScript -NonInteractive -Action DeployAll -PackagePath $Package.FullName

        # Capture exit code IMMEDIATELY (before any other command that might reset it)
        $exitCode = $LASTEXITCODE

        # Run OCR dependency check with auto-install
        Write-Log -Message "Checking and installing OCR dependencies..." -Level "INFO"
        & $consoleScript -NonInteractive -Action InstallOCR 2>&1 | ForEach-Object { Write-Log -Message $_ -Level "INFO" }

        Pop-Location

        # Check if exit code indicates success (0 = success)
        $deploySuccess = ($exitCode -eq 0)

        if ($deploySuccess) {
            Write-Success "Deployment completed successfully (exit code: $exitCode)"

            # Save deployment state
            Save-DeploymentState -DeploymentInfo @{
                PackageName = $Package.Name
                Component = "All"
                Status = "Success"
                Services = @{
                    backend = "Running (Ultrathin Monolith - All modules)"
                }
            }

            Write-Host "`n" + ("=" * 70) -ForegroundColor Green
            Write-Host "  DEPLOYMENT SUCCESSFUL" -ForegroundColor Green
            Write-Host ("=" * 70) -ForegroundColor Green

            return $true
        } else {
            Write-Error "Deployment failed (exit code: $exitCode)"

            # Save failure state
            Save-DeploymentState -DeploymentInfo @{
                PackageName = $Package.Name
                Component = "All"
                Status = "Failed"
                Services = @{}
            }

            Write-Host "`n" + ("=" * 70) -ForegroundColor Red
            Write-Host "  DEPLOYMENT FAILED" -ForegroundColor Red
            Write-Host ("=" * 70) -ForegroundColor Red

            return $false
        }
    } catch {
        Write-Error "Deployment exception: $_"
        Write-Log -Message $_.ScriptStackTrace -Level "ERROR"

        # Save failure state
        Save-DeploymentState -DeploymentInfo @{
            PackageName = $Package.Name
            Component = "All"
            Status = "Failed"
            Services = @{}
        }

        return $false
    }
}

# =============================================================================
# INTERACTIVE MENU
# =============================================================================

function Show-MainMenu {
    Clear-Host
    Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
    Write-Host "  ROA2WEB - Auto-Deploy Monitor (Interactive)" -ForegroundColor Cyan
    Write-Host ("=" * 70) -ForegroundColor Cyan
    Write-Host ""
    Write-Host "  [1] Check for Updates (No Deploy)" -ForegroundColor White
    Write-Host "      (Scan for new packages without deploying)" -ForegroundColor Gray
    Write-Host ""
    Write-Host "  [2] Check and Deploy Now" -ForegroundColor White
    Write-Host "      (Find latest package and deploy if new)" -ForegroundColor Gray
    Write-Host ""
    Write-Host "  [3] View Deployment History" -ForegroundColor White
    Write-Host "      (Show previous deployments)" -ForegroundColor Gray
    Write-Host ""
    Write-Host "  [4] View Current Configuration" -ForegroundColor White
    Write-Host "      (Display monitor settings)" -ForegroundColor Gray
    Write-Host ""
    Write-Host "  [Q] Quit" -ForegroundColor Red
    Write-Host ""
    Write-Host ("=" * 70) -ForegroundColor Cyan

    do {
        Write-Host "`nYour choice: " -ForegroundColor Yellow -NoNewline
        $choice = Read-Host

        switch ($choice.ToUpper()) {
            "1" { return "CheckOnly" }
            "2" { return "CheckAndDeploy" }
            "3" { return "History" }
            "4" { return "ViewConfig" }
            "Q" { return "Quit" }
            default {
                Write-Host "Invalid choice. Please select 1-4 or Q." -ForegroundColor Red
            }
        }
    } while ($true)
}

function Show-DeploymentHistory {
    Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
    Write-Host "  Deployment History" -ForegroundColor Cyan
    Write-Host ("=" * 70) -ForegroundColor Cyan

    $state = Get-DeploymentState

    if (-not $state) {
        Write-Host "`nNo deployment history found" -ForegroundColor Yellow
        return
    }

    if ($state.lastDeployment) {
        Write-Host "`nLast Deployment:" -ForegroundColor Yellow
        Write-Host "  Package:   $($state.lastDeployment.packageName)" -ForegroundColor Gray
        Write-Host "  Component: $($state.lastDeployment.component)" -ForegroundColor Gray
        Write-Host "  Timestamp: $($state.lastDeployment.timestamp)" -ForegroundColor Gray
        Write-Host "  Status:    $($state.lastDeployment.status)" -ForegroundColor $(if ($state.lastDeployment.status -eq "Success") { "Green" } else { "Red" })
    }

    if ($state.history -and $state.history.Count -gt 0) {
        Write-Host "`nPrevious Deployments:" -ForegroundColor Yellow
        $i = 1
        foreach ($entry in $state.history) {
            Write-Host "  [$i] $($entry.packageName) - $($entry.timestamp) - $($entry.status)" -ForegroundColor Gray
            $i++
        }
    }

    Write-Host ("=" * 70) -ForegroundColor Cyan
}

function Show-Configuration {
    Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
    Write-Host "  Current Configuration" -ForegroundColor Cyan
    Write-Host ("=" * 70) -ForegroundColor Cyan
    Write-Host ""
    Write-Host "  Watch Path:        $($script:Config.WatchPath)" -ForegroundColor Gray
    Write-Host "  State File:        $($script:Config.StateFile)" -ForegroundColor Gray
    Write-Host "  Log Path:          $($script:Config.LogPath)" -ForegroundColor Gray
    Write-Host "  Console Script:    $($script:Config.ConsoleScriptPath)" -ForegroundColor Gray
    Write-Host ""
    Write-Host ("=" * 70) -ForegroundColor Cyan
}

# =============================================================================
# MAIN CHECK & DEPLOY LOGIC
# =============================================================================

function Invoke-CheckAndDeploy {
    param([switch]$CheckOnly)

    Write-Log -Message "=== Check and Deploy Started ===" -Level "INFO"

    # Get latest package
    $latestPackage = Get-LatestDeploymentPackage

    if (-not $latestPackage) {
        Write-Log -Message "No deployment packages found" -Level "INFO"
        return $false
    }

    # Check if it's a new package
    $isNew = Test-IsNewPackage -Package $latestPackage

    if (-not $isNew) {
        Write-Log -Message "No new packages to deploy" -Level "INFO"
        return $false
    }

    if ($CheckOnly) {
        Write-Success "New package available: $($latestPackage.Name)"
        Write-Host "`nRun without -CheckOnly to deploy" -ForegroundColor Yellow
        return $false
    }

    # Deploy the package
    $deploySuccess = Invoke-Deployment -Package $latestPackage

    Write-Log -Message "=== Check and Deploy Completed (Success: $deploySuccess) ===" -Level "INFO"

    return $deploySuccess
}

# =============================================================================
# MAIN EXECUTION FLOW
# =============================================================================

function Main {
    # Check if running as Administrator
    $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
    $isAdmin = $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

    if (-not $isAdmin) {
        Write-Host "`n[ERROR] This script requires Administrator privileges" -ForegroundColor Red
        Write-Host "Please run PowerShell as Administrator and try again.`n" -ForegroundColor Yellow
        exit 1
    }

    # Interactive mode
    if ($Interactive) {
        do {
            $mainChoice = Show-MainMenu

            switch ($mainChoice) {
                "CheckOnly" {
                    Invoke-CheckAndDeploy -CheckOnly
                    Wait-ForKeyPress
                }

                "CheckAndDeploy" {
                    Invoke-CheckAndDeploy
                    Wait-ForKeyPress
                }

                "History" {
                    Show-DeploymentHistory
                    Wait-ForKeyPress
                }

                "ViewConfig" {
                    Show-Configuration
                    Wait-ForKeyPress
                }

                "Quit" {
                    Write-Host "`nGoodbye!`n" -ForegroundColor Cyan
                    return
                }
            }
        } while ($true)
    }
    # Non-interactive mode (for Scheduled Task)
    else {
        Invoke-CheckAndDeploy -CheckOnly:$CheckOnly | Out-Null
    }
}

# Run main
Main
