param(
    [Parameter(Mandatory = $true)]
    [ValidateSet('install', 'uninstall')]
    [string]$Operation,

    [Parameter(Mandatory = $true)]
    [string]$WspPath
)

$ErrorActionPreference = 'Stop'

$solutionName = 'WebsioPreviewField.wsp'
$timeout = New-TimeSpan -Minutes 10
$logDir = Split-Path -Parent $PSScriptRoot
if ([string]::IsNullOrWhiteSpace($logDir)) {
    $logDir = Join-Path $env:ProgramFiles 'Websio Information Solutions\Websio Document Preview 2026'
}
$logPath = Join-Path $logDir 'Install-WebsioPreviewSolution.log'
$transcriptStarted = $false

try {
    if (-not (Test-Path -LiteralPath $logDir)) {
        New-Item -ItemType Directory -Path $logDir -Force | Out-Null
    }

    Start-Transcript -Path $logPath -Append -Force | Out-Null
    $transcriptStarted = $true
}
catch {
    # Logging must never prevent installation; failures are still returned via exit code.
}

function Write-Step([string]$message) {
    Write-Host "[Websio Document Preview] $message"
}

function Show-InstallerMessage([string]$message) {
    try {
        $shell = New-Object -ComObject WScript.Shell
        $null = $shell.Popup($message, 0, 'Websio Document Preview 2026', 16)
    }
    catch {
        Write-Host $message
    }
}

function Fail([string]$message) {
    $fullMessage = "[Websio Document Preview] $message"
    Write-Host $fullMessage
    if ($script:transcriptStarted) {
        Stop-Transcript | Out-Null
    }
    Show-InstallerMessage $fullMessage
    exit 1
}

function Ensure-SharePointPowerShell {
    if (-not (Get-PSSnapin -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue)) {
        Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction Stop
    }
}

function Wait-SolutionJob([string]$name, [string]$action) {
    $deadline = (Get-Date).Add($timeout)

    while ((Get-Date) -lt $deadline) {
        $solution = Get-SPSolution -Identity $name -ErrorAction SilentlyContinue
        if ($null -eq $solution) {
            if ($action -eq 'delete') { return }
            Start-Sleep -Seconds 5
            continue
        }

        if (-not $solution.JobExists) {
            return
        }

        Start-Sleep -Seconds 5
    }

    Fail "Timed out waiting for SharePoint solution job '$action' on '$name'. Check SharePoint timer service and Central Administration."
}

function Retract-And-DeleteSolution([string]$name) {
    $solution = Get-SPSolution -Identity $name -ErrorAction SilentlyContinue
    if ($null -eq $solution) {
        Write-Step "SharePoint solution '$name' is not installed."
        return
    }

    if ($solution.Deployed) {
        Write-Step "Retracting existing SharePoint solution '$name'."
        Uninstall-SPSolution -Identity $name -Confirm:$false -ErrorAction Stop
        Wait-SolutionJob $name 'retract'
    }
    else {
        Write-Step "Existing SharePoint solution '$name' is already retracted."
    }

    Write-Step "Deleting existing SharePoint solution '$name'."
    Remove-SPSolution -Identity $name -Confirm:$false -ErrorAction Stop
    Wait-SolutionJob $name 'delete'
}

function Deploy-Solution([string]$name) {
    Write-Step "Deploying SharePoint solution '$name' as a farm-scoped global solution."
    Install-SPSolution -Identity $name -GACDeployment -Confirm:$false -ErrorAction Stop
    return 'deploy'
}

try {
    Write-Step "Starting SharePoint solution $Operation action."
    Write-Step "PowerShell: $($PSHOME)"
    Write-Step "User: $([Security.Principal.WindowsIdentity]::GetCurrent().Name)"
    Write-Step "WSP path: $WspPath"

    if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
        Fail "Installer custom action must run as Administrator. Run the MSI from an elevated administrator account. Detailed log: $logPath"
    }

    Ensure-SharePointPowerShell

    if ($Operation -eq 'install') {
        if (-not (Test-Path -LiteralPath $WspPath)) {
            Fail "WSP file was not found: $WspPath"
        }

        Retract-And-DeleteSolution $solutionName

        Write-Step "Adding SharePoint solution from '$WspPath'."
        Add-SPSolution -LiteralPath $WspPath -ErrorAction Stop | Out-Null

        $deployAction = Deploy-Solution $solutionName
        Wait-SolutionJob $solutionName $deployAction

        $solution = Get-SPSolution -Identity $solutionName -ErrorAction Stop
        if (-not $solution.Deployed) {
            Fail "SharePoint solution '$solutionName' was added but is not deployed."
        }

        Write-Step "SharePoint solution '$solutionName' was deployed successfully."
        if ($transcriptStarted) {
            Stop-Transcript | Out-Null
        }
        exit 0
    }

    Retract-And-DeleteSolution $solutionName
    Write-Step "SharePoint solution '$solutionName' was removed successfully."
    if ($transcriptStarted) {
        Stop-Transcript | Out-Null
    }
    exit 0
}
catch {
    Fail "$($_.Exception.Message). Detailed log: $logPath"
}
