<#
============================================================================
HammerDB Benchmark Automation - Windows Launcher (PowerShell)
============================================================================
This script automates the complete HammerDB benchmark workflow including:
- Pre-cleanup (delete existing schema, ignore errors)
- Schema build
- Test execution
- Result capture
- Post-cleanup

Configuration is read from config/appsettings.json

Usage:
  .\run.ps1 [-ConfigName <config_name>] [-ConfigFile <path_to_config.json>]

Parameters:
  -ConfigName    Name of the database configuration from the JSON file
                 If not provided and only one config exists, uses that automatically.
                 If multiple configs exist, prompts user to select.
  -ConfigFile    Optional path to custom config file (defaults to config/appsettings.json)

Examples:
  .\run.ps1                                    # Auto-select if only one config
  .\run.ps1 -ConfigName postgres-local         # Use specific config
  .\run.ps1 -ConfigName oracle-qa
============================================================================
#>

param(
    [Parameter(Mandatory=$false, HelpMessage="Name of the database configuration from the JSON file")]
    [string]$ConfigName,
    
    [Parameter(Mandatory=$false)]
    [string]$ConfigFile = "config\appsettings.json"
)

# Display header
Write-Host ""
Write-Host "============================================================================" -ForegroundColor Cyan
Write-Host "HammerDB Benchmark Automation Tool" -ForegroundColor Cyan
Write-Host "============================================================================" -ForegroundColor Cyan
Write-Host ""

# Get the directory where this script is located
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path

# Import encryption module (similar to migrate.ps1)
# Helper is located in tools\helper\ relative to the repository root, or in helper\ relative to script when packaged
$toolsRoot = Split-Path -Parent $ScriptDir
$encryptionModule = Join-Path $toolsRoot "helper\Helper-Encryption.psm1"

# If not found at tools root, try relative to script directory (for packaged artifact)
if (-not (Test-Path $encryptionModule)) {
    $encryptionModule = Join-Path $ScriptDir "helper\Helper-Encryption.psm1"
}

if (Test-Path $encryptionModule) {
    try {
        Import-Module $encryptionModule -Force
    } catch {
        Write-Host "WARNING: Could not import encryption module: $($_.Exception.Message)" -ForegroundColor Yellow
        Write-Host "Passwords will not be encrypted/decrypted." -ForegroundColor Yellow
    }
} else {
    Write-Host "WARNING: Encryption module not found. Tried:" -ForegroundColor Yellow
    Write-Host "  - $encryptionModule" -ForegroundColor Yellow
    Write-Host "Passwords will not be encrypted/decrypted." -ForegroundColor Yellow
}

# Import reporting modules
Write-Host "Loading reporting modules..." -ForegroundColor Cyan
$ModulesDir = Join-Path $ScriptDir "modules"
try {
    Import-Module (Join-Path $ModulesDir "ResultsData.psm1") -Force -ErrorAction Stop
    Import-Module (Join-Path $ModulesDir "MetricsParser.psm1") -Force -ErrorAction Stop
    Import-Module (Join-Path $ModulesDir "HtmlReportGenerator.psm1") -Force -ErrorAction Stop
    Import-Module (Join-Path $ModulesDir "CsvExportGenerator.psm1") -Force -ErrorAction Stop
    Import-Module (Join-Path $ModulesDir "TextReportGenerator.psm1") -Force -ErrorAction Stop
    Write-Host "Reporting modules loaded successfully" -ForegroundColor Green
} catch {
    Write-Error "Failed to load reporting modules: $_"
    exit 1
}
Write-Host ""

# Set up Oracle Instant Client environment
$OracleClientPath = Join-Path $ScriptDir "oracle-client"
if (Test-Path $OracleClientPath) {
    Write-Host "Configuring Oracle Instant Client environment..." -ForegroundColor Green
    
    # Set required Oracle environment variables
    $env:ORACLE_HOME = $OracleClientPath
    $env:PATH = "$OracleClientPath;$env:PATH"
    $env:TNS_ADMIN = Join-Path $OracleClientPath "network\admin"
    
    # Verify OCI.DLL is accessible
    $OciDll = Join-Path $OracleClientPath "oci.dll"
    if (Test-Path $OciDll) {
        Write-Host "  ORACLE_HOME: $OracleClientPath" -ForegroundColor Gray
        Write-Host "  TNS_ADMIN: $env:TNS_ADMIN" -ForegroundColor Gray
        Write-Host "  Oracle Instant Client configured successfully" -ForegroundColor Green
    } else {
        Write-Warning "Oracle Instant Client directory exists but oci.dll not found"
        Write-Host "  Oracle database tests may not work properly" -ForegroundColor Yellow
    }
} else {
    Write-Warning "Oracle Instant Client not found at $OracleClientPath"
    Write-Host "  Oracle database tests will not work" -ForegroundColor Yellow
}
Write-Host ""

# Validate HammerDB installation
$HammerDBCli = Join-Path $ScriptDir "hammerdb\hammerdbcli.exe"
if (-not (Test-Path $HammerDBCli)) {
    Write-Host "ERROR: HammerDB CLI not found at $HammerDBCli" -ForegroundColor Red
    Write-Host "Please ensure the hammerdb folder exists in the installation directory." -ForegroundColor Red
    Write-Host ""
    Read-Host "Press Enter to exit"
    exit 1
}
Write-Host "HammerDB CLI found: $HammerDBCli" -ForegroundColor Green
Write-Host ""

# Load configuration file
$ConfigPath = if ([System.IO.Path]::IsPathRooted($ConfigFile)) {
    $ConfigFile
} else {
    Join-Path $ScriptDir $ConfigFile
}

if (-not (Test-Path $ConfigPath)) {
    Write-Host "ERROR: Configuration file not found at $ConfigPath" -ForegroundColor Red
    Write-Host "Please create a config file or use the sample: config\appsettings.json" -ForegroundColor Yellow
    Write-Host ""
    Read-Host "Press Enter to exit"
    exit 1
}

Write-Host "Loading configuration from: $ConfigPath" -ForegroundColor Green

# Check for and convert any plaintext passwords (similar to migrate.ps1)
$null = Convert-PlaintextPasswordsInJson -JsonFilePath $ConfigPath

try {
    $Config = Get-Content $ConfigPath -Raw | ConvertFrom-Json
    # Decrypt password properties (similar to migrate.ps1)
    $Config = Unprotect-JsonPasswords -JsonObject $Config
} catch {
    Write-Host "ERROR: Failed to parse configuration file" -ForegroundColor Red
    Write-Host $_.Exception.Message -ForegroundColor Red
    Write-Host ""
    Read-Host "Press Enter to exit"
    exit 1
}

# Store original connection references (don't merge yet - will merge after type selection)
# This allows us to switch connections when user selects a different database type
if ($Config.connections) {
    foreach ($dbName in $Config.databases.PSObject.Properties.Name) {
        $dbConfig = $Config.databases.$dbName
        if ($dbConfig.connection) {
            $connName = $dbConfig.connection
            if (-not $Config.connections.$connName) {
                Write-Host "ERROR: Connection '$connName' not found for database '$dbName'" -ForegroundColor Red
                exit 1
            }
            # Store the connection name for later use (don't remove it yet)
            # We'll merge after the user selects the database type
        }
    }
}

# Get available database configurations
$AvailableConfigs = @($Config.databases.PSObject.Properties.Name)

if ($AvailableConfigs.Count -eq 0) {
    Write-Host "ERROR: No database configurations found in $ConfigPath" -ForegroundColor Red
    Write-Host "Please add at least one database configuration to the 'databases' section." -ForegroundColor Yellow
    Write-Host ""
    Read-Host "Press Enter to exit"
    exit 1
}

# Determine which config to use
if ([string]::IsNullOrWhiteSpace($ConfigName)) {
    # Auto-select the first available config
    $ConfigName = $AvailableConfigs[0]
    if ($AvailableConfigs.Count -eq 1) {
        Write-Host "Auto-selected configuration: $ConfigName (only one available)" -ForegroundColor Cyan
    } else {
        Write-Host "Auto-selected configuration: $ConfigName (first of $($AvailableConfigs.Count) available)" -ForegroundColor Cyan
    }
    Write-Host ""
}

# Verify the selected configuration exists
if (-not $Config.databases.PSObject.Properties.Name -contains $ConfigName) {
    Write-Host "ERROR: Configuration '$ConfigName' not found in $ConfigPath" -ForegroundColor Red
    Write-Host "Available configurations:" -ForegroundColor Yellow
    $AvailableConfigs | ForEach-Object { Write-Host "  - $_" -ForegroundColor Yellow }
    Write-Host ""
    Read-Host "Press Enter to exit"
    exit 1
}

# Prompt user to select database type
Write-Host "Select database type:" -ForegroundColor Yellow
Write-Host "  [1] PostgreSQL" -ForegroundColor Yellow
Write-Host "  [2] Oracle" -ForegroundColor Yellow
Write-Host ""

do {
    $dbSelection = Read-Host "Enter your choice (1 or 2)"
    $dbSelectionNum = 0
    $validSelection = [int]::TryParse($dbSelection, [ref]$dbSelectionNum) -and 
                      ($dbSelectionNum -eq 1 -or $dbSelectionNum -eq 2)
    
    if (-not $validSelection) {
        Write-Host "Invalid selection. Please enter 1 for PostgreSQL or 2 for Oracle." -ForegroundColor Red
    }
} while (-not $validSelection)

$SelectedDbType = if ($dbSelectionNum -eq 1) { "postgres" } else { "oracle" }
Write-Host ""
Write-Host "Selected database type: $SelectedDbType" -ForegroundColor Green
Write-Host ""

# Use the selected config
$DbConfig = $Config.databases.$ConfigName

# Find a connection that matches the selected database type
$MatchingConnection = $null
if ($Config.connections) {
    if ($DbConfig.connection) {
        # First, check if the original connection matches the selected type
        $originalConnName = $DbConfig.connection
        $originalConnection = $Config.connections.$originalConnName
        if ($originalConnection -and $originalConnection.type -eq $SelectedDbType) {
            $MatchingConnection = $originalConnection
        }
    }
    
    # If no matching connection found yet, look for any connection that matches the selected type
    if (-not $MatchingConnection) {
        $matchingConnections = $Config.connections.PSObject.Properties | Where-Object {
            $_.Value.type -eq $SelectedDbType
        }
        if ($matchingConnections.Count -eq 1) {
            $MatchingConnection = $matchingConnections[0].Value
        } elseif ($matchingConnections.Count -gt 1) {
            Write-Host "Multiple connections found for $SelectedDbType. Please select one:" -ForegroundColor Yellow
            $index = 1
            $connectionList = @()
            foreach ($conn in $matchingConnections) {
                Write-Host "  [$index] $($conn.Name) - $($conn.Value.host):$($conn.Value.port)" -ForegroundColor Yellow
                $connectionList += $conn
                $index++
            }
            Write-Host ""
            do {
                $connSelection = Read-Host "Enter your choice (1-$($connectionList.Count))"
                $connSelectionNum = 0
                $validConnSelection = [int]::TryParse($connSelection, [ref]$connSelectionNum) -and 
                                      ($connSelectionNum -ge 1 -and $connSelectionNum -le $connectionList.Count)
                if (-not $validConnSelection) {
                    Write-Host "Invalid selection. Please enter a number between 1 and $($connectionList.Count)." -ForegroundColor Red
                }
            } while (-not $validConnSelection)
            $MatchingConnection = $connectionList[$connSelectionNum - 1].Value
            Write-Host ""
        }
    }
}

# Merge connection properties into database config
if ($MatchingConnection) {
    # Clear existing connection-derived properties (but keep benchmark config)
    $propertiesToRemove = @('type', 'host', 'port', 'username', 'password', 'serviceName', 'database')
    foreach ($prop in $propertiesToRemove) {
        if ($DbConfig.PSObject.Properties.Name -contains $prop) {
            $DbConfig.PSObject.Properties.Remove($prop)
        }
    }
    
    # Merge connection properties (this will set type, host, port, username, password, serviceName, etc.)
    $MatchingConnection.PSObject.Properties | ForEach-Object {
        if ($_.Name -ne 'PSObject') {
            if ($DbConfig.PSObject.Properties.Name -contains $_.Name) {
                $DbConfig.$($_.Name) = $_.Value
            } else {
                $DbConfig | Add-Member -MemberType NoteProperty -Name $_.Name -Value $_.Value
            }
        }
    }
}

# Ensure type is set (in case no connection was found or merged)
if (-not $DbConfig.type) {
    $DbConfig.type = $SelectedDbType
}

# Remove connection reference if it exists (already merged)
if ($DbConfig.PSObject.Properties.Name -contains 'connection') {
    $DbConfig.PSObject.Properties.Remove('connection')
}

Write-Host "  Type: $($DbConfig.type)" -ForegroundColor Gray
Write-Host "  Host: $($DbConfig.host)" -ForegroundColor Gray
Write-Host "  Port: $($DbConfig.port)" -ForegroundColor Gray
Write-Host "  User: $($DbConfig.username)" -ForegroundColor Gray
Write-Host "  Password: ********" -ForegroundColor Gray
if ($DbConfig.serviceName) {
    Write-Host "  Service Name: $($DbConfig.serviceName)" -ForegroundColor Gray
}
Write-Host ""

# Determine database prefix
$DbPrefix = switch ($DbConfig.type) {
    "postgres" { "pg" }
    "oracle" { "ora" }
    default {
        Write-Host "ERROR: Unsupported database type: $($DbConfig.type)" -ForegroundColor Red
        Write-Host "Supported types: postgres, oracle" -ForegroundColor Yellow
        exit 1
    }
}

# Validate Oracle service name
if ($DbConfig.type -eq "oracle") {
    if ([string]::IsNullOrWhiteSpace($DbConfig.serviceName)) {
        Write-Host "Oracle database requires 'serviceName' in configuration" -ForegroundColor Yellow
        Write-Host "The selected configuration does not have a serviceName defined." -ForegroundColor Yellow
        Write-Host ""
        do {
            $serviceName = Read-Host "Please enter the Oracle service name (e.g., ORCL, XE, PROD)"
            if ([string]::IsNullOrWhiteSpace($serviceName)) {
                Write-Host "Service name cannot be empty. Please enter a valid service name." -ForegroundColor Red
            }
        } while ([string]::IsNullOrWhiteSpace($serviceName))
        
        # Add serviceName to the configuration
        if ($DbConfig.PSObject.Properties.Name -contains 'serviceName') {
            $DbConfig.serviceName = $serviceName
        } else {
            $DbConfig | Add-Member -MemberType NoteProperty -Name "serviceName" -Value $serviceName
        }
        Write-Host "Service name set to: $serviceName" -ForegroundColor Green
        Write-Host ""
    }
}

# Both TPROC-C and TPROC-H will run automatically
$BenchmarkTypes = @("TPROC-C", "TPROC-H")

# Function to find a config that matches database type and benchmark type
function Get-BenchmarkConfig {
    param(
        [string]$DbType,
        [string]$BenchmarkType
    )
    
    # First, try to find a config that matches both database type and benchmark type
    $matchingConfigs = $Config.databases.PSObject.Properties | Where-Object {
        $config = $_.Value
        $config.type -eq $DbType -and $config.benchmark -and $config.benchmark.type -eq $BenchmarkType
    }
    
    if ($matchingConfigs.Count -gt 0) {
        return $matchingConfigs[0].Value
    }
    
    # If not found, use the selected config and create a benchmark config with defaults
    # Create a copy to avoid modifying the original
    $configCopy = $DbConfig.PSObject.Copy()
    
    # Ensure benchmark object exists
    if (-not $configCopy.benchmark) {
        $configCopy | Add-Member -MemberType NoteProperty -Name "benchmark" -Value @{}
    }
    
    # Set the benchmark type
    $configCopy.benchmark.type = $BenchmarkType
    
    return $configCopy
}

# Capture the start timestamp when the script first runs (similar to hs1-jmeter)
$ScriptStartTime = Get-Date

# Create logs directory for raw HammerDB output
$LogsDir = Join-Path $ScriptDir "logs"
if (-not (Test-Path $LogsDir)) {
    New-Item -ItemType Directory -Path $LogsDir | Out-Null
}

# Create reports directory for processed results
$ReportsDir = Join-Path $ScriptDir "reports"
if (-not (Test-Path $ReportsDir)) {
    New-Item -ItemType Directory -Path $ReportsDir | Out-Null
}

# Format timestamp for use in file paths (filesystem-friendly format, same as hs1-jmeter)
$TimestampSuffix = $ScriptStartTime.ToString("yyyy-MM-dd_HH-mm-ss")
Write-Host "Script started at: $($ScriptStartTime.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Cyan

# Create timestamped folder for this test run (same as hs1-jmeter)
$TimestampedReportDir = Join-Path $ReportsDir $TimestampSuffix
if (-not (Test-Path $TimestampedReportDir)) {
    New-Item -ItemType Directory -Path $TimestampedReportDir -Force | Out-Null
    Write-Host "Created timestamped report directory: $TimestampedReportDir" -ForegroundColor Gray
}

# Generate timestamp for files (keep existing format for log filenames)
$Timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
$LogFile = Join-Path $LogsDir "hammerdb-$ConfigName-$Timestamp.log"

# Function to execute HammerDB CLI with a TCL script
function Invoke-HammerDBCli {
    param(
        [string]$TclScript,
        [string]$ScriptName,
        [bool]$IgnoreErrors = $false
    )
    
    $stepStart = Get-Date
    
    # Save TCL script to temp file
    $TempTcl = Join-Path $env:TEMP "hammerdb-$ScriptName-$Timestamp.tcl"
    Set-Content -Path $TempTcl -Value $TclScript -Encoding UTF8
    
    Write-Host "Executing $ScriptName..." -ForegroundColor Cyan
    
    # Execute HammerDB CLI
    $process = Start-Process -FilePath $HammerDBCli -ArgumentList "auto", $TempTcl -NoNewWindow -Wait -PassThru -RedirectStandardOutput "$env:TEMP\hammerdb-output-$Timestamp.txt" -RedirectStandardError "$env:TEMP\hammerdb-error-$Timestamp.txt"
    
    # Read output
    $output = Get-Content "$env:TEMP\hammerdb-output-$Timestamp.txt" -Raw -ErrorAction SilentlyContinue
    $errorOutput = Get-Content "$env:TEMP\hammerdb-error-$Timestamp.txt" -Raw -ErrorAction SilentlyContinue
    
    # Log output
    Add-Content -Path $LogFile -Value "=== $ScriptName ==="
    Add-Content -Path $LogFile -Value $output
    if ($errorOutput) {
        Add-Content -Path $LogFile -Value "ERRORS:"
        Add-Content -Path $LogFile -Value $errorOutput
    }
    Add-Content -Path $LogFile -Value ""
    
    # Display output
    Write-Host $output
    
    $stepEnd = Get-Date
    $duration = ($stepEnd - $stepStart).TotalSeconds
    
    # Check exit code
    $success = ($process.ExitCode -eq 0 -or $IgnoreErrors)
    if (-not $success -and -not $IgnoreErrors) {
        Write-Host "ERROR: $ScriptName failed with exit code $($process.ExitCode)" -ForegroundColor Red
        if ($errorOutput) {
            Write-Host $errorOutput -ForegroundColor Red
        }
        throw "$ScriptName failed"
    }
    
    # Cleanup temp files
    Remove-Item $TempTcl -ErrorAction SilentlyContinue
    Remove-Item "$env:TEMP\hammerdb-output-$Timestamp.txt" -ErrorAction SilentlyContinue
    Remove-Item "$env:TEMP\hammerdb-error-$Timestamp.txt" -ErrorAction SilentlyContinue
    
    # Return execution data
    return @{
        output = $output
        errorOutput = $errorOutput
        exitCode = $process.ExitCode
        duration = $duration
        startTime = $stepStart.ToString("o")
        endTime = $stepEnd.ToString("o")
        success = $success
    }
}

# Function to run workflow for a single benchmark type
function Run-BenchmarkWorkflow {
    param(
        [string]$BenchmarkType,
        [object]$BenchmarkConfig
    )
    
    Write-Host ""
    Write-Host "============================================================================" -ForegroundColor Cyan
    Write-Host "Starting $BenchmarkType Benchmark Workflow" -ForegroundColor Cyan
    Write-Host "============================================================================" -ForegroundColor Cyan
    Write-Host ""
    
    # Generate connection commands based on database type
    # Oracle: credentials in connection dictionary
    # PostgreSQL: only host/port in connection, credentials in benchmark dictionary
    if ($DbConfig.type -eq "oracle") {
        # Build Easy Connect string for Oracle: host:port/serviceName
        $OracleInstance = "$($DbConfig.host):$($DbConfig.port)/$($DbConfig.serviceName)"
        
        $ConnectionCommands = @"
diset connection system_user $($DbConfig.username)
diset connection system_password $($DbConfig.password)
diset connection instance $OracleInstance
"@
        $CredentialCommands = ""  # Oracle puts credentials in connection
    } else {
        # PostgreSQL: host/port in connection, credentials in benchmark dictionary
        $ConnectionCommands = @"
diset connection ${DbPrefix}_host $($DbConfig.host)
diset connection ${DbPrefix}_port $($DbConfig.port)
"@
        
        # PostgreSQL credentials go in the benchmark dictionary (tpcc or tpch)
        if ($BenchmarkType -eq "TPROC-C") {
            $CredentialCommands = @"
diset tpcc ${DbPrefix}_superuser $($DbConfig.username)
diset tpcc ${DbPrefix}_superuserpass $($DbConfig.password)
"@
        } else {
            # TPROC-H
            $CredentialCommands = @"
diset tpch ${DbPrefix}_tpch_superuser $($DbConfig.username)
diset tpch ${DbPrefix}_tpch_superuserpass $($DbConfig.password)
"@
        }
    }

    # Generate TCL scripts based on benchmark type
    Write-Host "Generating TCL scripts for $BenchmarkType workflow..." -ForegroundColor Cyan
    
    # Get benchmark-specific settings with defaults
    if ($BenchmarkType -eq "TPROC-C") {
        $warehouses = if ($BenchmarkConfig.benchmark.build.warehouses) { $BenchmarkConfig.benchmark.build.warehouses } else { 100 }
        $buildVUs = if ($BenchmarkConfig.benchmark.build.virtualUsers) { $BenchmarkConfig.benchmark.build.virtualUsers } else { 8 }
        $testVUs = if ($BenchmarkConfig.benchmark.test.virtualUsers) { $BenchmarkConfig.benchmark.test.virtualUsers } else { 5 }
        $rampupMinutes = if ($BenchmarkConfig.benchmark.test.rampupMinutes) { $BenchmarkConfig.benchmark.test.rampupMinutes } else { 2 }
        $durationMinutes = if ($BenchmarkConfig.benchmark.test.durationMinutes) { $BenchmarkConfig.benchmark.test.durationMinutes } else { 10 }
        $TotalMinutes = $rampupMinutes + $durationMinutes
    } else {
        $scaleFactor = if ($BenchmarkConfig.benchmark.build.scaleFactor) { $BenchmarkConfig.benchmark.build.scaleFactor } else { 1 }
        $buildVUs = if ($BenchmarkConfig.benchmark.build.virtualUsers) { $BenchmarkConfig.benchmark.build.virtualUsers } else { 8 }
        $testVUs = if ($BenchmarkConfig.benchmark.test.virtualUsers) { $BenchmarkConfig.benchmark.test.virtualUsers } else { 5 }
        $totalQuerySets = if ($BenchmarkConfig.benchmark.test.totalQuerySets) { $BenchmarkConfig.benchmark.test.totalQuerySets } else { 10 }
        $degreeOfParallelism = if ($BenchmarkConfig.benchmark.test.degreeOfParallelism) { $BenchmarkConfig.benchmark.test.degreeOfParallelism } else { 2 }
        $TotalMinutes = $null
    }
    
    # Generate TCL scripts differently for TPROC-C vs TPROC-H
    if ($BenchmarkType -eq "TPROC-C") {
    # Pre-Cleanup TCL for TPROC-C
    $PreCleanupTcl = @"
#!/usr/bin/tclsh
puts "=== Pre-Cleanup: Deleting existing TPROC-C schema if exists ==="
dbset db $DbPrefix
dbset bm TPROC-C
$ConnectionCommands
$CredentialCommands
catch {deleteschema} result
puts "Pre-cleanup result: `$result"
puts "=== Pre-Cleanup Complete (errors ignored) ==="
"@

    # Build Schema TCL for TPROC-C
    $BuildSchemaTcl = @"
#!/usr/bin/tclsh
puts "=== Building TPROC-C Schema for $($DbConfig.type) ==="
dbset db $DbPrefix
dbset bm TPROC-C
$ConnectionCommands
$CredentialCommands
diset tpcc $(if ($DbConfig.type -eq "oracle") { "count_ware" } else { "${DbPrefix}_count_ware" }) $warehouses
diset tpcc $(if ($DbConfig.type -eq "oracle") { "num_vu" } else { "${DbPrefix}_num_vu" }) $buildVUs
vuset logtotemp 1
puts "Building new schema..."
buildschema
vudestroy
puts "=== Schema Build Complete ==="
"@

    # Run Test TCL for TPROC-C
    $RunTestTcl = @"
#!/usr/bin/tclsh
puts "=== Running TPROC-C Test for $($DbConfig.type) ==="
dbset db $DbPrefix
dbset bm TPROC-C
$ConnectionCommands
$CredentialCommands
diset tpcc $(if ($DbConfig.type -eq "oracle") { "ora_driver" } else { "${DbPrefix}_driver" }) timed
diset tpcc $(if ($DbConfig.type -eq "oracle") { "rampup" } else { "${DbPrefix}_rampup" }) $rampupMinutes
diset tpcc $(if ($DbConfig.type -eq "oracle") { "duration" } else { "${DbPrefix}_duration" }) $durationMinutes
vuset vu $testVUs
vuset logtotemp 1
puts "Loading driver script..."
loadscript
puts "Creating virtual users..."
vucreate
puts "Running test (this will take approximately $TotalMinutes minutes)..."
vurun
puts "Test execution complete, cleaning up virtual users..."
vudestroy
puts "=== Test Complete ==="
puts "Results saved to HammerDB temp log directory"
"@

    # Post-Cleanup TCL for TPROC-C
    $PostCleanupTcl = @"
#!/usr/bin/tclsh
puts "=== Post-Cleanup: Deleting TPROC-C Schema for $($DbConfig.type) ==="
dbset db $DbPrefix
dbset bm TPROC-C
$ConnectionCommands
$CredentialCommands
puts "Deleting schema..."
deleteschema
puts "=== Post-Cleanup Complete - Database is clean ==="
"@

} elseif ($BenchmarkType -eq "TPROC-H") {
    # TPROC-H uses tpch dictionary for benchmark parameters
    
    # Pre-Cleanup TCL for TPROC-H
    $PreCleanupTcl = @"
#!/usr/bin/tclsh
puts "=== Pre-Cleanup: Deleting existing TPROC-H schema if exists ==="
dbset db $DbPrefix
dbset bm TPROC-H
$ConnectionCommands
$CredentialCommands
catch {deleteschema} result
puts "Pre-cleanup result: `$result"
puts "=== Pre-Cleanup Complete (errors ignored) ==="
"@

    # Build Schema TCL for TPROC-H
    $BuildSchemaTcl = @"
#!/usr/bin/tclsh
puts "=== Building TPROC-H Schema for $($DbConfig.type) ==="
dbset db $DbPrefix
dbset bm TPROC-H
$ConnectionCommands
$CredentialCommands
diset tpch $(if ($DbConfig.type -eq "oracle") { "scale_fact" } else { "${DbPrefix}_scale_fact" }) $scaleFactor
diset tpch $(if ($DbConfig.type -eq "oracle") { "num_tpch_threads" } else { "${DbPrefix}_num_tpch_threads" }) $buildVUs
vuset logtotemp 1
puts "Building new schema..."
buildschema
vudestroy
puts "=== Schema Build Complete ==="
"@

    # Run Test TCL for TPROC-H
    $RunTestTcl = @"
#!/usr/bin/tclsh
puts "=== Running TPROC-H Test for $($DbConfig.type) ==="
dbset db $DbPrefix
dbset bm TPROC-H
$ConnectionCommands
$CredentialCommands
diset tpch $(if ($DbConfig.type -eq "oracle") { "total_querysets" } else { "${DbPrefix}_total_querysets" }) $totalQuerySets
diset tpch $(if ($DbConfig.type -eq "oracle") { "degree_of_parallel" } else { "${DbPrefix}_degree_of_parallel" }) $degreeOfParallelism
vuset vu $testVUs
vuset logtotemp 1
puts "Loading driver script..."
loadscript
puts "Creating virtual users..."
vucreate
puts "Running test..."
vurun
puts "Test execution complete, cleaning up virtual users..."
vudestroy
puts "=== Test Complete ==="
puts "Results saved to HammerDB temp log directory"
"@

    # Post-Cleanup TCL for TPROC-H
    $PostCleanupTcl = @"
#!/usr/bin/tclsh
puts "=== Post-Cleanup: Deleting TPROC-H Schema for $($DbConfig.type) ==="
dbset db $DbPrefix
dbset bm TPROC-H
$ConnectionCommands
$CredentialCommands
puts "Deleting schema..."
deleteschema
puts "=== Post-Cleanup Complete - Database is clean ==="
"@
}

    Write-Host "TCL scripts generated successfully for $BenchmarkType" -ForegroundColor Green
    Write-Host ""
    
    # Initialize results data structure
    $resultsData = New-BenchmarkResults
    $resultsData.metadata.configName = "$ConfigName-$BenchmarkType"
    $resultsData.metadata.timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $resultsData.metadata.timestampUtc = (Get-Date).ToUniversalTime().ToString("o")
    
    # Create a temporary config object with the benchmark type set
    $tempDbConfig = $DbConfig.PSObject.Copy()
    
    # Copy benchmark config if it exists, otherwise create a new one
    if ($BenchmarkConfig.benchmark) {
        $tempDbConfig.benchmark = $BenchmarkConfig.benchmark.PSObject.Copy()
    } else {
        $tempDbConfig | Add-Member -MemberType NoteProperty -Name "benchmark" -Value @{} -Force
    }
    $tempDbConfig.benchmark.type = $BenchmarkType
    
    # Populate database and benchmark info
    Set-DatabaseInfo -ResultsData $resultsData -DbConfig $tempDbConfig
    Set-BenchmarkInfo -ResultsData $resultsData -DbConfig $tempDbConfig
    
    $workflowSuccess = $false
    $workflowStart = Get-Date

try {
    # Step 1: Pre-cleanup
    Write-Host "Step 1/5: Pre-cleanup (deleting existing schema if present)..." -ForegroundColor Yellow
    $stepResult = Invoke-HammerDBCli -TclScript $PreCleanupTcl -ScriptName "pre-cleanup" -IgnoreErrors $true
    Add-ExecutionStep -ResultsData $resultsData -StepName "pre-cleanup" -Duration $stepResult.duration -StartTime $stepResult.startTime -EndTime $stepResult.endTime -Success $stepResult.success
    Write-Host "Pre-cleanup completed" -ForegroundColor Green
    Write-Host ""
    
    # Step 2: Build Schema
    Write-Host "Step 2/5: Building schema (this may take 10-30 minutes)..." -ForegroundColor Yellow
    if ($BenchmarkType -eq "TPROC-C") {
        Write-Host "  Warehouses: $warehouses" -ForegroundColor Gray
        Write-Host "  Build Virtual Users: $buildVUs" -ForegroundColor Gray
    } else {
        Write-Host "  Scale Factor: $scaleFactor" -ForegroundColor Gray
        Write-Host "  Build Threads: $buildVUs" -ForegroundColor Gray
    }
    $stepResult = Invoke-HammerDBCli -TclScript $BuildSchemaTcl -ScriptName "build-schema"
    $buildOutput = $stepResult.output
    Add-ExecutionStep -ResultsData $resultsData -StepName "build-schema" -Duration $stepResult.duration -StartTime $stepResult.startTime -EndTime $stepResult.endTime -Success $stepResult.success
    Write-Host "Schema build completed" -ForegroundColor Green
    Write-Host ""
    
    # Step 3: Run Test
    if ($BenchmarkType -eq "TPROC-C") {
        Write-Host "Step 3/5: Running test (approximately $TotalMinutes minutes)..." -ForegroundColor Yellow
        Write-Host "  Test Virtual Users: $testVUs" -ForegroundColor Gray
        Write-Host "  Rampup Time: $rampupMinutes minutes" -ForegroundColor Gray
        Write-Host "  Test Duration: $durationMinutes minutes" -ForegroundColor Gray
    } else {
        Write-Host "Step 3/5: Running test..." -ForegroundColor Yellow
        Write-Host "  Test Virtual Users: $testVUs" -ForegroundColor Gray
        Write-Host "  Total Query Sets: $totalQuerySets" -ForegroundColor Gray
        Write-Host "  Degree of Parallelism: $degreeOfParallelism" -ForegroundColor Gray
    }
    $stepResult = Invoke-HammerDBCli -TclScript $RunTestTcl -ScriptName "run-test"
    $testOutput = $stepResult.output
    Add-ExecutionStep -ResultsData $resultsData -StepName "run-test" -Duration $stepResult.duration -StartTime $stepResult.startTime -EndTime $stepResult.endTime -Success $stepResult.success
    Write-Host "Test execution completed" -ForegroundColor Green
    Write-Host ""
    
    # Step 4: Post-cleanup
    Write-Host "Step 4/5: Post-cleanup (deleting schema)..." -ForegroundColor Yellow
    $stepResult = Invoke-HammerDBCli -TclScript $PostCleanupTcl -ScriptName "post-cleanup"
    Add-ExecutionStep -ResultsData $resultsData -StepName "post-cleanup" -Duration $stepResult.duration -StartTime $stepResult.startTime -EndTime $stepResult.endTime -Success $stepResult.success
    Write-Host "Post-cleanup completed" -ForegroundColor Green
    Write-Host ""
    
    # Step 5: Capture Results and Generate Reports
    Write-Host "Step 5/5: Capturing results and generating reports..." -ForegroundColor Yellow
    
    $workflowEnd = Get-Date
    $resultsData.execution.startTime = $workflowStart.ToString("o")
    $resultsData.execution.endTime = $workflowEnd.ToString("o")
    $resultsData.execution.totalDurationSeconds = ($workflowEnd - $workflowStart).TotalSeconds
    
    # Parse metrics based on benchmark type
    if ($BenchmarkType -eq "TPROC-C") {
        $resultsData.results.metrics = Parse-TPROCCMetrics -Output $testOutput
    } else {
        $resultsData.results.metrics = Parse-TPROCHMetrics -Output $testOutput
    }
    
    # Mark workflow as successful (we reached this point without exceptions)
    $workflowSuccess = $true
    $resultsData.results.success = $workflowSuccess
    
    # Generate output files
    $baseFileName = "hammerdb-$ConfigName-$BenchmarkType-$Timestamp"
    
    # 1. JSON (primary storage format)
    $jsonFile = Join-Path $TimestampedReportDir "$baseFileName.json"
    $resultsData | ConvertTo-Json -Depth 10 | Set-Content -Path $jsonFile -Encoding UTF8
    
    # 2. HTML Report
    $htmlFile = Join-Path $TimestampedReportDir "$baseFileName.html"
    $htmlContent = New-HtmlReport -ResultsData $resultsData
    Set-Content -Path $htmlFile -Value $htmlContent -Encoding UTF8
    
    # 3. CSV Exports
    $csvSummaryFile = Join-Path $TimestampedReportDir "$baseFileName-summary.csv"
    Export-SummaryToCsv -ResultsData $resultsData -OutputPath $csvSummaryFile
    
    $csvVuFile = Join-Path $TimestampedReportDir "$baseFileName-virtualusers.csv"
    Export-VirtualUsersToCsv -ResultsData $resultsData -OutputPath $csvVuFile
    
    $csvTimelineFile = Join-Path $TimestampedReportDir "$baseFileName-timeline.csv"
    Export-ExecutionTimelineToCsv -ResultsData $resultsData -OutputPath $csvTimelineFile
    
    # 4. Text Summary
    $txtFile = Join-Path $TimestampedReportDir "$baseFileName-results.txt"
    $textContent = New-TextReport -ResultsData $resultsData
    Set-Content -Path $txtFile -Value $textContent -Encoding UTF8
    
    # Display summary
    Write-Host ""
    Write-Host "============================================================================" -ForegroundColor Cyan
    Write-Host "BENCHMARK RESULTS SUMMARY" -ForegroundColor Cyan
    Write-Host "============================================================================" -ForegroundColor Cyan
    $metricsSummary = Get-MetricsSummary -Metrics $resultsData.results.metrics -BenchmarkType $BenchmarkType
    Write-Host $metricsSummary -ForegroundColor Green
    Write-Host ""
    
    Write-Host "Reports generated:" -ForegroundColor Green
    Write-Host "  JSON:     $jsonFile" -ForegroundColor Gray
    Write-Host "  HTML:     $htmlFile" -ForegroundColor Gray
    Write-Host "  CSV:      $csvSummaryFile" -ForegroundColor Gray
    Write-Host "  CSV (VU): $csvVuFile" -ForegroundColor Gray
    Write-Host "  CSV (TL): $csvTimelineFile" -ForegroundColor Gray
    Write-Host "  Text:     $txtFile" -ForegroundColor Gray
    Write-Host ""
    Write-Host "Raw execution log:" -ForegroundColor Cyan
    Write-Host "  Log:      $LogFile" -ForegroundColor Gray
    Write-Host ""
    
} catch {
    Write-Host ""
    Write-Host "ERROR: Workflow failed - $($_.Exception.Message)" -ForegroundColor Red
    Write-Host ""
    
    # Attempt cleanup even on failure
    Write-Host "Attempting cleanup after failure..." -ForegroundColor Yellow
    try {
        $stepResult = Invoke-HammerDBCli -TclScript $PostCleanupTcl -ScriptName "post-cleanup-after-error" -IgnoreErrors $true
        Add-ExecutionStep -ResultsData $resultsData -StepName "post-cleanup-after-error" -Duration $stepResult.duration -StartTime $stepResult.startTime -EndTime $stepResult.endTime -Success $stepResult.success
        Write-Host "Cleanup completed" -ForegroundColor Green
    } catch {
        Write-Host "Cleanup failed, but continuing..." -ForegroundColor Yellow
    }
    
    # Generate failure report
    $workflowEnd = Get-Date
    $resultsData.execution.startTime = $workflowStart.ToString("o")
    $resultsData.execution.endTime = $workflowEnd.ToString("o")
    $resultsData.execution.totalDurationSeconds = ($workflowEnd - $workflowStart).TotalSeconds
    $resultsData.results.success = $false
    $resultsData.results.errors += $_.Exception.Message
    
    # Generate minimal reports for failed run
    $baseFileName = "hammerdb-$ConfigName-$BenchmarkType-$Timestamp"
    $jsonFile = Join-Path $TimestampedReportDir "$baseFileName.json"
    $resultsData | ConvertTo-Json -Depth 10 | Set-Content -Path $jsonFile -Encoding UTF8
    
    Write-Host ""
    Write-Host "Failure report saved to: $jsonFile" -ForegroundColor Yellow
}
    
    return $workflowSuccess
}

# Run both benchmark types automatically
$allBenchmarksSuccess = $true
foreach ($BenchmarkType in $BenchmarkTypes) {
    Write-Host ""
    Write-Host "============================================================================" -ForegroundColor Magenta
    Write-Host "Running $BenchmarkType Benchmark" -ForegroundColor Magenta
    Write-Host "============================================================================" -ForegroundColor Magenta
    
    # Get benchmark-specific config
    $BenchmarkConfig = Get-BenchmarkConfig -DbType $DbConfig.type -BenchmarkType $BenchmarkType
    
    # Run the workflow for this benchmark type
    $benchmarkSuccess = Run-BenchmarkWorkflow -BenchmarkType $BenchmarkType -BenchmarkConfig $BenchmarkConfig
    
    if (-not $benchmarkSuccess) {
        $allBenchmarksSuccess = $false
        Write-Host ""
        Write-Host "WARNING: $BenchmarkType benchmark failed, but continuing with next benchmark..." -ForegroundColor Yellow
    }
}

# Display final completion message
Write-Host ""
Write-Host "============================================================================" -ForegroundColor Cyan
if ($allBenchmarksSuccess) {
    Write-Host "All Benchmarks Completed Successfully!" -ForegroundColor Green
    $exitCode = 0
} else {
    Write-Host "Some Benchmarks Failed" -ForegroundColor Red
    Write-Host ""
    Write-Host "Check log file for details: $LogFile" -ForegroundColor Yellow
    $exitCode = 1
}
Write-Host "============================================================================" -ForegroundColor Cyan
Write-Host ""

Read-Host "Press Enter to exit"
exit $exitCode
