$ErrorActionPreference = "Stop"

$MsysRootWin = "C:/msys64"
$MsysRootNative = "C:\msys64"
$MsysRootUnix = "/c/msys64"
$Msys2DistUrl = "https://repo.msys2.org/distrib/x86_64/"
$DownloadDir = Join-Path $env:TEMP "msys2-installer"

New-Item -ItemType Directory -Force -Path $DownloadDir | Out-Null

Write-Host "==> Finding latest MSYS2 installer..."

$page = Invoke-WebRequest -Uri $Msys2DistUrl -UseBasicParsing
$installerName = [regex]::Matches($page.Content, "msys2-x86_64-[0-9]{8}\.exe") |
        ForEach-Object { $_.Value } |
        Sort-Object -Unique |
        Select-Object -Last 1

if (-not $installerName) {
    throw "Could not find latest MSYS2 installer."
}

$installerUrl = "$Msys2DistUrl$installerName"
$installerPath = Join-Path $DownloadDir $installerName

Write-Host "==> Latest installer: $installerName"
Write-Host "==> URL: $installerUrl"

if (-not (Test-Path $installerPath)) {
    Write-Host "==> Downloading installer..."
    Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath
} else {
    Write-Host "==> Installer already exists: $installerPath"
}

Write-Host "==> Installing MSYS2 to $MsysRootWin..."

if (Test-Path "$MsysRootNative\usr\bin\bash.exe") {
    Write-Host "==> MSYS2 already exists, skipping installer."
} else {
    $env:MSYS2_ARG_CONV_EXCL = "*"

    $args = @(
        "in",
        "--confirm-command",
        "--accept-messages",
        "--root",
        $MsysRootWin
    )

    $p = Start-Process -FilePath $installerPath -ArgumentList $args -Wait -PassThru

    if ($p.ExitCode -ne 0) {
        throw "MSYS2 installer failed. Exit code: $($p.ExitCode)"
    }
}

$MsysBash = "$MsysRootNative\usr\bin\bash.exe"

if (-not (Test-Path $MsysBash)) {
    throw "MSYS2 bash not found: $MsysBash"
}

function Invoke-Msys {
    param(
        [Parameter(Mandatory = $true)]
        [string] $Command,

        [switch] $IgnoreExitCode
    )

    Write-Host ""
    Write-Host "==> MSYS2: $Command"

    & $MsysBash -lc $Command
    $code = $LASTEXITCODE

    if ($code -ne 0) {
        Write-Host "MSYS2 command exit code: $code"

        if (-not $IgnoreExitCode) {
            throw "MSYS2 command failed: $Command"
        }
    }
}

Write-Host "==> Initializing MSYS2..."
Invoke-Msys "exit"

Write-Host "==> Updating MSYS2 core system..."
Write-Host "==> First pacman -Syuu may terminate inner bash. This is expected."

Invoke-Msys "pacman -Syuu --noconfirm" -IgnoreExitCode
Start-Sleep -Seconds 5

Invoke-Msys "pacman -Syuu --noconfirm" -IgnoreExitCode
Start-Sleep -Seconds 3

Invoke-Msys "pacman -Syuu --noconfirm" -IgnoreExitCode
Start-Sleep -Seconds 3

Write-Host "==> Installing UCRT64 MinGW toolchain and packages..."

$packages = @(
    "git",
    "make",
    "patch",
    "diffutils",
    "mingw-w64-ucrt-x86_64-gcc",
    "mingw-w64-ucrt-x86_64-cmake",
    "mingw-w64-ucrt-x86_64-ninja",
    "mingw-w64-ucrt-x86_64-openssl",
    "mingw-w64-ucrt-x86_64-pkgconf",
    "mingw-w64-ucrt-x86_64-gdb",
    "mingw-w64-ucrt-x86_64-make"
)

$packageLine = $packages -join " "

Invoke-Msys "pacman -S --needed --noconfirm $packageLine"

Write-Host "==> Checking installed tools..."

Invoke-Msys @"
export PATH=/ucrt64/bin:`$PATH
echo gcc:
gcc --version | head -n 1
echo g++:
g++ --version | head -n 1
echo cmake:
cmake --version | head -n 1
echo ninja:
ninja --version
echo gdb:
gdb --version | head -n 1
echo openssl:
openssl version
echo pkg-config openssl:
pkg-config --modversion openssl
"@

Write-Host ""
Write-Host "============================================================"
Write-Host "Done."
Write-Host ""
Write-Host "CLion toolchain paths:"
Write-Host "C compiler:   C:\msys64\ucrt64\bin\gcc.exe"
Write-Host "C++ compiler: C:\msys64\ucrt64\bin\g++.exe"
Write-Host "Debugger:     C:\msys64\ucrt64\bin\gdb.exe"
Write-Host "CMake:        C:\msys64\ucrt64\bin\cmake.exe"
Write-Host "Ninja:        C:\msys64\ucrt64\bin\ninja.exe"
Write-Host ""
Write-Host "CMake OpenSSL option:"
Write-Host "-DOPENSSL_ROOT_DIR=C:/msys64/ucrt64"
Write-Host ""
Write-Host "OpenSSL include:"
Write-Host "C:\msys64\ucrt64\include"
Write-Host ""
Write-Host "OpenSSL libs:"
Write-Host "C:\msys64\ucrt64\lib\libssl.dll.a"
Write-Host "C:\msys64\ucrt64\lib\libcrypto.dll.a"
Write-Host "============================================================"