[CmdletBinding()]
param(
    [switch]$Configure
)

$ErrorActionPreference = 'Stop'
$marRoot = $PSScriptRoot
$settingsDirectory = Join-Path $marRoot 'Configuration'
$settingsPath = Join-Path $settingsDirectory 'deployment-settings.json'
$configPaths = @(
    (Join-Path $marRoot 'Home11\Config\OA3Tool-ServerBased.cfg'),
    (Join-Path $marRoot 'Pro11\Config\OA3Tool-ServerBased.cfg'),
    (Join-Path $marRoot 'Cit11\Config\OA3Tool-ServerBased.cfg')
)

function Test-ValidIpv4Address
{
    param([string]$Address)

    $parsedAddress = $null
    return [System.Net.IPAddress]::TryParse($Address, [ref]$parsedAddress) -and
        $parsedAddress.AddressFamily -eq [System.Net.Sockets.AddressFamily]::InterNetwork
}

function Read-DeploymentSettings
{
    if(-not (Test-Path -LiteralPath $settingsPath -PathType Leaf))
    {
        return $null
    }

    try
    {
        return Get-Content -LiteralPath $settingsPath -Raw | ConvertFrom-Json
    }
    catch
    {
        Write-Warning "The saved MAR deployment settings are unreadable. New values are required."
        return $null
    }
}

function Read-RequiredSettings
{
    do
    {
        $businessId = (Read-Host 'Enter the MDOS Business ID').Trim()
        if($businessId -notmatch '^[A-Za-z0-9_-]{1,64}$')
        {
            Write-Host 'Business ID must contain 1-64 letters, numbers, underscores, or hyphens.' -ForegroundColor Yellow
        }
    } while($businessId -notmatch '^[A-Za-z0-9_-]{1,64}$')

    do
    {
        $serverIpAddress = (Read-Host 'Enter the MDOS Smart Client / SFTP server IPv4 address').Trim()
        if(-not (Test-ValidIpv4Address -Address $serverIpAddress))
        {
            Write-Host 'Enter a valid IPv4 address, for example 192.0.2.10.' -ForegroundColor Yellow
        }
    } while(-not (Test-ValidIpv4Address -Address $serverIpAddress))

    return [pscustomobject]@{
        BusinessId = $businessId
        ServerIpAddress = $serverIpAddress
    }
}

try
{
    $settings = Read-DeploymentSettings
    $settingsAreValid = $null -ne $settings -and
        $settings.PSObject.Properties.Name -contains 'BusinessId' -and
        $settings.PSObject.Properties.Name -contains 'ServerIpAddress' -and
        $settings.BusinessId -match '^[A-Za-z0-9_-]{1,64}$' -and
        (Test-ValidIpv4Address -Address $settings.ServerIpAddress)

    if($Configure -or -not $settingsAreValid)
    {
        Write-Host ''
        Write-Host 'MAR deployment configuration is required.' -ForegroundColor Cyan
        $settings = Read-RequiredSettings
    }

    foreach($configPath in $configPaths)
    {
        if(-not (Test-Path -LiteralPath $configPath -PathType Leaf))
        {
            throw "Required configuration file was not found: $configPath"
        }

        [xml]$configXml = Get-Content -LiteralPath $configPath -Raw
        # Property shorthand returns a string for these elements; SelectSingleNode returns writable XmlElement objects.
        $serverNode = $configXml.SelectSingleNode('/OA3/ServerBased/KeyProviderServerLocation/IPAddress')
        $businessIdNode = $configXml.SelectSingleNode('/OA3/ServerBased/Parameters/BusinessID')
        if($null -eq $serverNode -or $null -eq $businessIdNode)
        {
            throw "Required IPAddress or BusinessID element is missing from $configPath"
        }

        $serverNode.InnerText = $settings.ServerIpAddress
        $businessIdNode.InnerText = $settings.BusinessId

        $backupPath = "$configPath.bak"
        Copy-Item -LiteralPath $configPath -Destination $backupPath -Force
        $temporaryPath = "$configPath.$([guid]::NewGuid().ToString('N')).tmp"
        try
        {
            $configXml.Save($temporaryPath)
            Move-Item -LiteralPath $temporaryPath -Destination $configPath -Force
        }
        finally
        {
            Remove-Item -LiteralPath $temporaryPath -Force -ErrorAction SilentlyContinue
        }
    }

    if(-not (Test-Path -LiteralPath $settingsDirectory -PathType Container))
    {
        New-Item -ItemType Directory -Path $settingsDirectory -Force | Out-Null
    }
    $settingsToSave = [pscustomobject]@{
        BusinessId = [string]$settings.BusinessId
        ServerIpAddress = [string]$settings.ServerIpAddress
        UpdatedUtc = [DateTime]::UtcNow.ToString('o')
    }
    $temporarySettingsPath = "$settingsPath.$([guid]::NewGuid().ToString('N')).tmp"
    try
    {
        $settingsToSave | ConvertTo-Json | Set-Content -LiteralPath $temporarySettingsPath -Encoding UTF8
        Move-Item -LiteralPath $temporarySettingsPath -Destination $settingsPath -Force
    }
    finally
    {
        Remove-Item -LiteralPath $temporarySettingsPath -Force -ErrorAction SilentlyContinue
    }

    Write-Host "MAR configuration applied. Business ID: $($settings.BusinessId); MDOS/SFTP IP: $($settings.ServerIpAddress)" -ForegroundColor Green
    exit 0
}
catch
{
    Write-Host "MAR configuration failed: $($_.Exception.Message)" -ForegroundColor Red
    exit 1
}
