param(
    [ValidateSet("auto", "x64", "x86")]
    [string]$Architecture = "auto"
)

$ErrorActionPreference = "Stop"

if (Get-Process EXCEL -ErrorAction SilentlyContinue) {
    throw "Excel is running. Close Excel before installing OctaveExcel."
}

function Get-OfficeArchitecture {
    param([string]$Requested)

    if ($Requested -ne "auto") {
        return $Requested
    }

    $paths = @(
        'HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration',
        'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\ClickToRun\Configuration'
    )

    foreach ($path in $paths) {
        $config = Get-ItemProperty $path -ErrorAction SilentlyContinue
        if ($config -and $config.Platform -in @("x64", "x86")) {
            return [string]$config.Platform
        }
    }

    if ([Environment]::Is64BitOperatingSystem) {
        Write-Warning "Excel bitness could not be detected. Assuming 64-bit Excel. Use -Architecture x86 if needed."
        return "x64"
    }

    return "x86"
}

function Find-Xll {
    param([string]$Arch)

    $name = if ($Arch -eq "x64") { "OctaveExcel-x64.xll" } else { "OctaveExcel-x86.xll" }

    $candidates = @(
        (Join-Path $PSScriptRoot $name),
        (Join-Path (Join-Path $PSScriptRoot "dist") $name)
    )

    foreach ($candidate in $candidates) {
        if (Test-Path $candidate) {
            return (Resolve-Path $candidate).Path
        }
    }

    throw "$name was not found. Build the project first, or run the installer from the release package."
}

function Get-ExcelOptionsKey {
    $officeRoot = 'HKCU:\Software\Microsoft\Office'

    if (Test-Path $officeRoot) {
        $versions = Get-ChildItem $officeRoot -ErrorAction SilentlyContinue |
            Where-Object { $_.PSChildName -match '^\d+\.\d+$' } |
            Sort-Object { [version]$_.PSChildName } -Descending

        foreach ($version in $versions) {
            $excelKey = Join-Path $version.PSPath "Excel"
            if (Test-Path $excelKey) {
                $optionsKey = Join-Path $excelKey "Options"
                if (-not (Test-Path $optionsKey)) {
                    New-Item $optionsKey -Force | Out-Null
                }
                return $optionsKey
            }
        }
    }

    $fallback = 'HKCU:\Software\Microsoft\Office\16.0\Excel\Options'
    if (-not (Test-Path $fallback)) {
        New-Item $fallback -Force | Out-Null
    }
    return $fallback
}

function Get-OpenIndex {
    param([string]$Name)

    if ($Name -eq "OPEN") {
        return 0
    }

    if ($Name -match '^OPEN(\d+)$') {
        return [int]$Matches[1]
    }

    return [int]::MaxValue
}

function Rewrite-OpenValues {
    param(
        [string]$Key,
        [string]$NewValue
    )

    $properties = Get-ItemProperty $Key

    $existing = @(
        $properties.PSObject.Properties |
            Where-Object { $_.Name -match '^OPEN\d*$' -and [string]$_.Value -notlike '*OctaveExcel*' } |
            Sort-Object { Get-OpenIndex $_.Name } |
            ForEach-Object { [string]$_.Value }
    )

    $allOpenNames = @(
        $properties.PSObject.Properties |
            Where-Object { $_.Name -match '^OPEN\d*$' } |
            ForEach-Object { $_.Name }
    )

    foreach ($name in $allOpenNames) {
        Remove-ItemProperty -Path $Key -Name $name -ErrorAction SilentlyContinue
    }

    $values = @($existing) + @($NewValue)

    for ($i = 0; $i -lt $values.Count; $i++) {
        $name = if ($i -eq 0) { "OPEN" } else { "OPEN$i" }
        New-ItemProperty -Path $Key -Name $name -PropertyType String -Value $values[$i] -Force | Out-Null
    }
}

$arch = Get-OfficeArchitecture -Requested $Architecture
$xll = Find-Xll -Arch $arch
$optionsKey = Get-ExcelOptionsKey

Unblock-File $xll -ErrorAction SilentlyContinue

$openValue = '/R "' + $xll + '"'
Rewrite-OpenValues -Key $optionsKey -NewValue $openValue

Write-Host "OctaveExcel 1.0.0 installed for $arch Excel." -ForegroundColor Green
Write-Host "Add-in: $xll"
Write-Host ""
Write-Host "Open Excel and verify:"
Write-Host "  =octaveaddinversion()"
Write-Host "  =octaveversion()"
Write-Host "  =octavefn(""airy"",0,0)"
