#!/usr/bin/pwsh

param(
    [Alias('h')][switch]$SHOW_HELP,
    [Alias('m')][string]$HOME_DIR="",
    [Alias('p')][string]$PROXY_URL,
    [Alias('s')][string]$SERVER_ID,
    [Alias('x')][switch]$SKIP_SERVICE_PROMPT
)

$ErrorActionPreference = "Stop"

If ($SHOW_HELP) {
    Write-Host "DESCRIPTION: Install Anypoint Monitoring OpenTelemetry Collector"
    Write-Host "Usage: .\$($MyInvocation.MyCommand) [options]"
    Write-Host ""
    Write-Host "options:"
    Write-Host "-h          show help and exit"
    Write-Host "-m [DIR]    set home directory - defaults to MULE_HOME"
    Write-Host "-p [URL]    set SOCKS5 proxy server URL"
    Write-Host "            Example: socks5://user:password@socks5-server:1080"
    Write-Host "-s [ID]     set server ID"
    Write-Host "-x          skip service installation prompt"
    Write-Host ""
    exit 0
}

# Configure home directory
if ([string]::IsNullOrEmpty($HOME_DIR) -Or (-Not (Test-Path -Path $HOME_DIR))) {
    if (-Not ([string]::IsNullOrEmpty($Env:MULE_HOME)) -And (Test-Path -Path $Env:MULE_HOME)) {
        $HOME_DIR=$Env:MULE_HOME
    }
    else {
        cd $(split-path -parent $MyInvocation.MyCommand.Definition)
        cd ..\..
        $HOME_DIR=Convert-Path $pwd
    }
}

# Source the serviceHelper.ps1
. (Join-Path -Path $HOME_DIR -ChildPath "am\bin\tools\serviceHelper.ps1")

Log-Info "MULE_HOME is set to $HOME_DIR"

# Set AM_HOME based on the determined HOME_DIR
$env:AM_HOME = Join-Path -Path $HOME_DIR -ChildPath "am"
$env:AM_CONFIG = Join-Path -Path $env:AM_HOME -ChildPath "config"
$env:AM_CONFIG_PIPELINES = Join-Path -Path $env:AM_HOME -ChildPath "config\pipelines"

$env:OTEL_COLLECTOR_EXE = Join-Path $env:AM_HOME "otel-collector\windows\otel-collector.exe"
$env:OTEL_COLLECTOR_DATA = Join-Path -Path $HOME_DIR -ChildPath ".mule\.am\otel-collector\data"
$env:OTEL_COLLECTOR_LOGS = Join-Path -Path $env:AM_HOME -ChildPath "logs"

# Check for system-wide GOMEMLIMIT and set if not present
$currentGoMemLimit = [System.Environment]::GetEnvironmentVariable("GOMEMLIMIT", [System.EnvironmentVariableTarget]::Machine)

if ($currentGoMemLimit) {
    $env:GOMEMLIMIT = $currentGoMemLimit
    Log-Info "System-wide GOMEMLIMIT is already set to $currentGoMemLimit. Reusing it."
} else {
    # Compute GOMEMLIMIT based on OTEL_PROCESSOR_MEMORY_LIMIT_MB or default to 40
    if ($env:OTEL_PROCESSOR_MEMORY_LIMIT_MB) {
        $memLimit = [int]$env:OTEL_PROCESSOR_MEMORY_LIMIT_MB
    } else {
        # Inspired by otel-pipeline-common.yml
        # processors:
        #  memory_limiter:
        #    check_interval: 1s
        #    limit_mib: 40
        $memLimit = 40
    }
    $goMemLimit = [math]::Floor($memLimit * 0.67)
    $gomemlimitValue = "${goMemLimit}MiB"

    # Set as system-wide (machine) environment variable
    [System.Environment]::SetEnvironmentVariable("GOMEMLIMIT", $gomemlimitValue, [System.EnvironmentVariableTarget]::Machine)
    $env:GOMEMLIMIT = $gomemlimitValue
    Log-Info "System-wide GOMEMLIMIT set to $gomemlimitValue"
}

# Ensure OTEL_COLLECTOR_DATA directory exists
if (-not (Test-Path $env:OTEL_COLLECTOR_DATA)) {
    New-Item -Path $env:OTEL_COLLECTOR_DATA -ItemType Directory -Force | Out-Null
}

# Ensure OTEL_COLLECTOR_LOGS directory exists
if (-not (Test-Path $env:OTEL_COLLECTOR_LOGS)) {
    New-Item -Path $env:OTEL_COLLECTOR_LOGS -ItemType Directory -Force | Out-Null
}

$modeFile = Join-Path $env:AM_HOME "install.mode"

$serviceScript = Join-Path -Path $env:AM_HOME -ChildPath "bin\am-service.ps1"
#$processScript = Join-Path -Path $env:AM_HOME -ChildPath "bin\am.ps1"

# Source the am-service.ps1 script
. "$serviceScript"


Write-Output "AM_HOME is set to $env:AM_HOME"

# Initialize configuration files
function Initialize-ConfigFiles {
    # Remove existing pipeline configuration files
    Remove-Item $env:AM_HOME\config\pipelines\*.yml -Force -ErrorAction SilentlyContinue

    # Check if SERVER_ID is set
    if (-not $SERVER_ID) {
        # Remove server.id if SERVER_ID is not set
        Remove-Item $env:AM_HOME\config\server.id -Force -ErrorAction SilentlyContinue
    } else {
        # Create and set server.id with SERVER_ID
        Set-Content -Value $Utf8NoBomEncoding.GetBytes($SERVER_ID) -Encoding Byte -Path $env:AM_HOME\config\server.id
    }
}

# Configure proxy URL
function Invoke-ConfigureProxyUrl {
    # Remove existing proxy URL file
    Remove-Item $env:AM_HOME\config\proxy.url -Force -ErrorAction SilentlyContinue

    # Determine the proxy value
    $proxyValue = if ($PROXY_URL) { $PROXY_URL } else { $Env:HTTPS_PROXY }

    # Check if the proxy value is set
    if ($proxyValue) {
        # Write the proxy URL to the file
        Set-Content -Value $Utf8NoBomEncoding.GetBytes($proxyValue) -Encoding Byte -Path $env:AM_HOME\config\proxy.url
        Log-Info "Set the proxy to $proxyValue."
    }
}

# Configure agent
function Invoke-ConfigureAgent {
    Log-Info "Configuring agent..."

    # Check if Java is available
    if (Get-Command java -ErrorAction SilentlyContinue) {
        Log-Info "Java is available at: $((Get-Command java).Source)"
        
        # Run the Java-based configurator
        $jarPath = Join-Path -Path $env:AM_HOME -ChildPath "lib\agent-configurator.jar"
        if (Test-Path $jarPath) {
            Log-Info "Found agent-configurator.jar at: $jarPath"
            try {
                Log-Info "Starting Java process with arguments: -jar `"$jarPath`" `"${HOME_DIR}`""
                $process = Start-Process -FilePath "java" -ArgumentList "-jar `"$jarPath`" `"${HOME_DIR}`"" -NoNewWindow -Wait -PassThru -RedirectStandardOutput "$env:AM_HOME\logs\agent-configurator.log" -RedirectStandardError "$env:AM_HOME\logs\agent-configurator.err"
                
                Log-Info "Java process completed with exit code: $($process.ExitCode)"
                if (Test-Path "$env:AM_HOME\logs\agent-configurator.log") {
                    Log-Info "Agent configurator output:"
                    Get-Content "$env:AM_HOME\logs\agent-configurator.log"
                }

                if (Test-Path "$env:AM_HOME\logs\agent-configurator.log") {
                    $logContent = Get-Content "$env:AM_HOME\logs\agent-configurator.log" -Raw
                    if (-not [string]::IsNullOrWhiteSpace($logContent)) {
                        Log-Info "Agent configurator output:"
                        Write-Host $logContent
                    }
                }

                if (Test-Path "$env:AM_HOME\logs\agent-configurator.err") {
                    $errContent = Get-Content "$env:AM_HOME\logs\agent-configurator.err" -Raw
                    if (-not [string]::IsNullOrWhiteSpace($errContent)) {
                        Log-Info "Agent configurator errors:"
                        Write-Host $errContent
                    }
                }
                
                if ($process.ExitCode -ne 0) {
                    Log-Info "Error: Failed to configure agent. Exit code: $($process.ExitCode)"
                    Log-Info "Please ensure no other processes are using the agent files and try again."
                    exit 1
                }
            } catch {
                Log-Info "Error: Failed to configure agent: $_"
                Log-Info "Please ensure no other processes are using the agent files and try again."
                exit 1
            }
        } else {
            Log-Info "Error: agent-configurator.jar not found at: $jarPath"
            exit 1
        }
    } else {
        Log-Info "Error: Java is not installed or not in PATH"
        exit 1
    }
}

# Function to create PID file
function Create-PidFile {
    param(
        [bool]$IsService,
        [string]$BaseDir
    )
    
    try {
        if ($IsService) {
            # For service mode, use elevated privileges
            # Start-Process -FilePath "powershell.exe" -ArgumentList "-Command `"New-Item -Path '$BaseDir' -ItemType Directory -Force; New-Item -Path '$BaseDir\am-agent.pid' -ItemType File -Force`"" -Verb RunAs -Wait
        } else {
            # For standalone mode, use current user privileges
            New-Item -Path $BaseDir -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null
            New-Item -Path (Join-Path -Path $BaseDir -ChildPath "am-agent.pid") -ItemType File -Force -ErrorAction SilentlyContinue | Out-Null
        }
    } catch {
        Log-Info "Warning: Failed to create PID file: $_"
    }
}

$SERVICE_NAME="am-otel-collector"

function Set-Recovery {
    param(
        [string]
        [Parameter(Mandatory=$true)]
        $ServiceName
    )
    sc.exe failure $ServiceName reset= 60000 actions= restart/60000
}

# Initialize configuration files
Initialize-ConfigFiles

# Configure proxy URL
Invoke-ConfigureProxyUrl

# Configure agent
Invoke-ConfigureAgent

# Handle service installation
if ($SKIP_SERVICE_PROMPT) {
    # Create pid file only if running as a process
    Create-PidFile -IsService $false -BaseDir $env:AM_HOME
    Set-Content -Path $modeFile -Value "process"
    Write-Host "Skipping service installation prompt. Anypoint Monitoring OpenTelemetry Collector will run as a standalone process."
} else {
    $REPLY = Read-Host -Prompt "Do you want to use monitoring as a service? [y|n]"
    if ($REPLY -eq 'y') {
        Set-Content -Path $modeFile -Value "service"
        Write-Host "Anypoint Monitoring OpenTelemetry Collector will run as a Windows service."
    } else {
        # Create pid file only if running as a process
        Create-PidFile -IsService $false -BaseDir $env:AM_HOME
        Set-Content -Path $modeFile -Value "process"
        Write-Host "Anypoint Monitoring OpenTelemetry Collector will run as a standalone process."
    }
}

# This script will prompt you to choose whether to run Anypoint Monitoring as a Windows service or as a standalone
# process. Your choice is saved in the 'install.mode' file, so the system knows which mode to use for future
# start/stop commands. We do not rely on the am-agent.pid file for this, because that file is deleted when the
# process stops, and would not reliably indicate your chosen mode. Even if the service cannot be installed now
# (for example, if configuration files are missing), you can still follow the standard installation steps.