param(
    [string]$WebsiteRoot = (Join-Path $PSScriptRoot '..\Webseite'),
    [string]$Version = '1.5.2',
    [string]$ReleaseDate = '01.09.2026'
)

$ErrorActionPreference = 'Stop'
$WebsiteRoot = [IO.Path]::GetFullPath($WebsiteRoot)
$projectRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
$releaseRoot = [IO.Path]::GetFullPath((Join-Path $projectRoot "release\$Version"))
$downloadsRoot = [IO.Path]::GetFullPath((Join-Path $WebsiteRoot 'downloads'))
$currentDownloadRoot = [IO.Path]::GetFullPath((Join-Path $downloadsRoot $Version))
$utf8NoBom = [Text.UTF8Encoding]::new($false)
$invariant = [Globalization.CultureInfo]::InvariantCulture

function Assert-DirectChild([string]$Parent, [string]$Child) {
    $resolvedParent = [IO.Path]::GetFullPath($Parent).TrimEnd('\')
    $resolvedChild = [IO.Path]::GetFullPath($Child)
    if ([IO.Path]::GetDirectoryName($resolvedChild).TrimEnd('\') -ne $resolvedParent) {
        throw "Refusing to modify a path outside the expected directory: $resolvedChild"
    }
}

if (-not (Test-Path -LiteralPath $releaseRoot -PathType Container)) {
    throw "Release directory is missing: $releaseRoot"
}
$manifestPath = Join-Path $releaseRoot 'release-manifest.json'
$manifest = Get-Content -LiteralPath $manifestPath -Raw | ConvertFrom-Json
if ($manifest.version -ne $Version -or $manifest.securityGate -ne 'passed') {
    throw "Release $Version is not a matching, completed security-gated release."
}

New-Item -ItemType Directory -Force -Path $downloadsRoot | Out-Null
Assert-DirectChild $downloadsRoot $currentDownloadRoot
if (Test-Path -LiteralPath $currentDownloadRoot) {
    Remove-Item -LiteralPath $currentDownloadRoot -Recurse -Force
}
New-Item -ItemType Directory -Force -Path $currentDownloadRoot | Out-Null
Copy-Item -Path (Join-Path $releaseRoot '*') -Destination $currentDownloadRoot -Recurse -Force

# Only the newest published release remains in the website download directory.
Get-ChildItem -LiteralPath $downloadsRoot -Directory |
    Where-Object { $_.Name -ne $Version } |
    ForEach-Object {
        Assert-DirectChild $downloadsRoot $_.FullName
        Remove-Item -LiteralPath $_.FullName -Recurse -Force
    }

function Release-Size([string]$RelativePath) {
    $bytes = (Get-Item -LiteralPath (Join-Path $releaseRoot $RelativePath)).Length
    return ($bytes / 1MB).ToString('0.0', $invariant) + ' MiB'
}

$windowsSize = Release-Size "windows\ArxSilex-MapTools-Converter-$Version-windows-x64.zip"
$linuxSize = Release-Size "linux\ArxSilex-MapTools-Converter-$Version-linux-x64.tar.gz"
$sourceSize = Release-Size "source\ArxSilex-MapTools-Converter-$Version-src.zip"
$cacheToken = '20260901c'

$indexPages = @((Join-Path $WebsiteRoot 'index.html'))
$indexPages += Get-ChildItem -LiteralPath $WebsiteRoot -Directory |
    ForEach-Object { Join-Path $_.FullName 'index.html' } |
    Where-Object { Test-Path -LiteralPath $_ }

$androidDownloadLabels = @{
    'index.html'          = 'MapTools Android herunterladen'
    'en\index.html'      = 'Download MapTools for Android'
    'fr\index.html'      = 'Télécharger MapTools pour Android'
    'es\index.html'      = 'Descargar MapTools para Android'
    'it\index.html'      = 'Scarica MapTools per Android'
    'pt\index.html'      = 'Transferir MapTools para Android'
    'nl\index.html'      = 'MapTools voor Android downloaden'
    'pl\index.html'      = 'Pobierz MapTools na Androida'
    'cs\index.html'      = 'Stáhnout MapTools pro Android'
    'tr\index.html'      = "Android için MapTools'u indir"
    'uk\index.html'      = 'Завантажити MapTools для Android'
    'ja\index.html'      = 'Android版MapToolsをダウンロード'
    'ko\index.html'      = 'Android용 MapTools 다운로드'
    'zh-Hans\index.html' = '下载 Android 版 MapTools'
    'ru\index.html'      = 'Скачать MapTools для Android'
    'ro\index.html'      = 'Descarcă MapTools pentru Android'
    'sv\index.html'      = 'Hämta MapTools för Android'
}

foreach ($page in $indexPages) {
    $relative = [IO.Path]::GetRelativePath($WebsiteRoot, $page)
    $html = [IO.File]::ReadAllText($page)
    $html = [Text.RegularExpressions.Regex]::Replace($html, 'downloads/\d+\.\d+\.\d+', "downloads/$Version")
    $html = [Text.RegularExpressions.Regex]::Replace(
        $html,
        'ArxSilex-MapTools-Converter-\d+\.\d+\.\d+',
        "ArxSilex-MapTools-Converter-$Version"
    )
    $html = [Text.RegularExpressions.Regex]::Replace($html, '"softwareVersion":"[^"]+"', '"softwareVersion":"' + $Version + '"')
    $html = [Text.RegularExpressions.Regex]::Replace($html, '"dateModified":"[^"]+"', '"dateModified":"2026-09-01"')
    $html = [Text.RegularExpressions.Regex]::Replace($html, 'v=\d+[a-z]?', "v=$cacheToken")

    if ($relative -eq 'index.html') {
        $html = $html.Replace(
            'Portabler Desktop-Konverter für OSM-PBF- und Mapsforge-Kartendaten.',
            'Portabler Desktop-Konverter für Karten-, POI- und Höhendaten.'
        )
        $html = $html.Replace(
            'Wähle lokale Kartendaten, grenze ein Gebiet ein und erzeuge passende Mapsforge-Karten, POI-Daten oder einen PBF-Ausschnitt.',
            'Wähle lokale Karten-, POI- oder Höhendaten, grenze ein Gebiet ein und exportiere genau den benötigten Ausschnitt.'
        )
        $html = $html.Replace(
            '<article class="text-card"><h3>Quellen</h3><p>Öffne lokale .osm.pbf-, .pbf-, Mapsforge-.map- und .poi-Dateien. Eine .map und eine ergänzende .poi können gemeinsam geladen werden; auch reine .poi-Dateien lassen sich zuschneiden.</p></article>',
            '<article class="text-card"><h3>Quellen</h3><p>Öffne Karten-, POI- und Höhendateien einzeln, gemeinsam oder aus sicher geprüften ZIP-Dateien. Mehrere .map- und .poi-Quellen werden geografisch kombiniert; reine POI- und Höhendaten lassen sich ebenfalls zuschneiden.</p></article>'
        )
        $html = $html.Replace(
            '<article class="text-card"><h3>Export</h3><p>Aus einer .map entstehen wahlweise Map, POI oder beide; aus einer reinen .poi nur POI. Bei .map plus .poi liefert die Karte die Kartendaten und die POI-Datei Suche und POI-Ausgabe. Unterstützt werden Map v4/v5 und POI v3/v4.</p></article>',
            '<article class="text-card"><h3>Export</h3><p>Erzeuge je nach Quellen Mapsforge .map v4/v5, eine zusammengeführte .poi v3/v4, zugeschnittenes OSM-PBF oder Höhendaten in GeoTIFF, ASC, HGT oder DTED. Bei Karten plus POIs stammen Kartendaten aus den Kartenquellen und POIs aus allen geladenen POI-Datenbanken.</p></article>'
        )
    } elseif ($relative -eq 'en\index.html') {
        $html = $html.Replace(
            'Portable desktop converter for OSM PBF and Mapsforge map data.',
            'Portable desktop converter for map, POI and elevation data.'
        )
        $html = $html.Replace(
            'Choose local map data, define an area and create suitable Mapsforge maps, POI data or a PBF extract.',
            'Choose local map, POI or elevation data, define an area and export exactly the extract you need.'
        )
        $html = $html.Replace(
            '<article class="text-card"><h3>Sources</h3><p>Open local .osm.pbf, .pbf, Mapsforge .map and .poi files. One .map and one companion .poi can be loaded together, and POI-only files can also be cropped.</p></article>',
            '<article class="text-card"><h3>Sources</h3><p>Open map, POI and elevation files separately, together or from security-checked ZIP files. Multiple .map and .poi sources are combined geographically; POI-only and elevation-only data can also be clipped.</p></article>'
        )
        $html = $html.Replace(
            '<article class="text-card"><h3>Export</h3><p>A .map source can create a map, POI data or both; a POI-only source creates POI data only. With .map plus .poi, the map supplies map output while the POI file supplies search and POI output. Map v4/v5 and POI v3/v4 are supported.</p></article>',
            '<article class="text-card"><h3>Export</h3><p>Create Mapsforge .map v4/v5, one merged .poi v3/v4, a clipped OSM PBF or elevation data as GeoTIFF, ASC, HGT or DTED, depending on the sources. With maps plus POIs, map data comes from the map sources and POIs from every loaded POI database.</p></article>'
        )
    }

    $html = [Text.RegularExpressions.Regex]::Replace(
        $html,
        '<section class="section light" id="converter-license">.*?</section><section class="section light" id="converter-downloads">.*?</section>',
        {
            param($match)
            $block = [Text.RegularExpressions.Regex]::Replace($match.Value, '\b1\.\d+\.\d+\b', $Version)
            $block = [Text.RegularExpressions.Regex]::Replace($block, '\b(?:28|31)\.08\.2026\b', $ReleaseDate)
            $block = [Text.RegularExpressions.Regex]::Replace(
                $block,
                '<article class="text-card">.*?</article>',
                {
                    param($articleMatch)
                    $article = $articleMatch.Value
                    $size = if ($article -match 'windows-x64\.zip') {
                        $windowsSize
                    } elseif ($article -match 'linux-x64\.tar\.gz') {
                        $linuxSize
                    } elseif ($article -match '-src\.zip') {
                        $sourceSize
                    } else {
                        $null
                    }
                    if ($size) {
                        $article = [Text.RegularExpressions.Regex]::Replace(
                            $article,
                            '<strong>[^<]+</strong>',
                            "<strong>$size</strong>",
                            1
                        )
                        $article = [Text.RegularExpressions.Regex]::Replace(
                            $article,
                            '<p>Version \d+\.\d+\.\d+</p>',
                            "<p>MapTools Converter $Version · $ReleaseDate</p>"
                        )
                    }
                    return $article
                },
                [Text.RegularExpressions.RegexOptions]::Singleline
            )
            return $block
        },
        [Text.RegularExpressions.RegexOptions]::Singleline
    )

    if ($relative -eq 'index.html') {
        $releaseCard = '<article class="text-card"><h3>MapTools Converter 1.5.2</h3><p>Beim Skalieren eines Auswahlkreises bleibt der vorhandene Radius beim Anklicken eines Eckgriffs jetzt unverändert. Erst die tatsächliche Ziehbewegung vergrößert oder verkleinert den Kreis gleichmäßig, ohne dass die Kreislinie beim Start springt.</p></article>'
    } else {
        $releaseCard = '<article class="text-card"><h3>MapTools Converter 1.5.2</h3><p>When resizing a circular selection, pressing a corner handle now preserves the existing radius. Only the actual drag movement scales the circle, so its outline no longer jumps when the gesture starts.</p></article>'
    }
    $html = [Text.RegularExpressions.Regex]::Replace(
        $html,
        '<article class="text-card"><h3>(?:Version|MapTools Converter) \d+\.\d+\.\d+</h3>.*?</article>',
        $releaseCard,
        [Text.RegularExpressions.RegexOptions]::Singleline
    )

    $androidDownloadLabel = $androidDownloadLabels[$relative]
    if ($androidDownloadLabel) {
        $html = [Text.RegularExpressions.Regex]::Replace(
            $html,
            '(<a class="btn btn-ghost" href="https://www\.arxsilex\.de/app/maptools/(?:[^"]*/)?download\.html">)[^<]+(</a>)',
            ('$1' + $androidDownloadLabel + '$2')
        )
    }
    [IO.File]::WriteAllText($page, $html, $utf8NoBom)
}

$changelogPages = @((Join-Path $WebsiteRoot 'changelog.html'))
$changelogPages += Get-ChildItem -LiteralPath $WebsiteRoot -Directory |
    ForEach-Object { Join-Path $_.FullName 'changelog.html' } |
    Where-Object { Test-Path -LiteralPath $_ }

foreach ($page in $changelogPages) {
    $relative = [IO.Path]::GetRelativePath($WebsiteRoot, $page)
    $homepageHref = if ($relative -eq 'changelog.html') { './' } else { './index.html' }
    $main = @"
<main id="main">
<section class="page-hero"><div class="wrap"><p class="pill">ArxSilex MapTools Converter</p><h1>Changelog</h1><p>Public release history of the desktop application.</p></div></section>
<section class="section light release-history" id="current-release">
  <p class="release-current-version">Current release: <code>$Version</code> <span>· 1 September 2026</span></p>
  <div class="table-wrap" tabindex="0">
    <table class="release-table">
      <thead><tr><th scope="col">Release</th><th scope="col">Date</th><th scope="col">Changes</th></tr></thead>
      <tbody>
        <tr><td><span class="release-version"><strong>1.5.2</strong></span></td><td>1 Sep 2026</td><td>Prevented circular selections from jumping in size when resizing starts on a bounding-box handle.</td></tr>
        <tr><td><span class="release-version">1.5.1</span></td><td>1 Sep 2026</td><td>Greatly accelerated large HGT-to-GeoTIFF exports with adaptive CPU and memory use, parallel buffered strips, geographic source indexing and exact selection-row intervals.</td></tr>
        <tr><td><span class="release-version">1.5.0</span></td><td>1 Sep 2026</td><td>Import, preview, search, clip and merge any number of POI databases. Mixed v3/v4 inputs are normalized, IDs and category trees are remapped, and exact boundary duplicates are removed.</td></tr>
        <tr><td><span class="release-version">1.4.0</span></td><td>1 Sep 2026</td><td>Added security-checked ZIP imports containing any supported mixture of map, POI and elevation files.</td></tr>
        <tr><td><span class="release-version">1.3.1</span></td><td>1 Sep 2026</td><td>Added the packaged Java naming module required to inspect and import GeoTIFF elevation files.</td></tr>
        <tr><td><span class="release-version">1.3.0</span></td><td>1 Sep 2026</td><td>Added offline terrain previews for elevation-only and combined map-and-elevation workflows.</td></tr>
        <tr><td><span class="release-version">1.2.0</span></td><td>1 Sep 2026</td><td>Added HGT, GeoTIFF, ESRI ASCII Grid and DTED import, clipping, conversion and export.</td></tr>
        <tr><td><span class="release-version">1.1.0</span></td><td>31 Aug 2026</td><td>Added complete-job progress, elapsed and estimated remaining time, and safe parallel map/POI output on suitable systems.</td></tr>
        <tr><td><span class="release-version">1.0.4</span></td><td>31 Aug 2026</td><td>Improved selection visibility with transparent dark-petrol fills and a gold active outline.</td></tr>
        <tr><td><span class="release-version">1.0.3</span></td><td>31 Aug 2026</td><td>Kept Back and Continue actions visible while workflow content scrolls at smaller window sizes.</td></tr>
        <tr><td><span class="release-version">1.0.2</span></td><td>31 Aug 2026</td><td>Added disk-backed processing for large Mapsforge sources and rate-limited progress output.</td></tr>
        <tr><td><span class="release-version">1.0.1</span></td><td>28 Aug 2026</td><td>Improved scrolling at smaller window sizes and reliability for large Mapsforge conversions.</td></tr>
        <tr><td><span class="release-version">1.0.0</span></td><td>28 Aug 2026</td><td>First public version.</td></tr>
      </tbody>
    </table>
  </div>
  <div class="hero-actions after-table"><a class="btn btn-primary" href="$homepageHref">ArxSilex MapTools Converter</a></div>
</section>
</main>
"@

    $html = [IO.File]::ReadAllText($page)
    $html = [Text.RegularExpressions.Regex]::Replace($html, '<main id="main">.*?</main>', $main.Trim(), [Text.RegularExpressions.RegexOptions]::Singleline)
    $html = $html.Replace(
        'Portabler Desktop-Konverter für OSM-PBF- und Mapsforge-Kartendaten.',
        'Portabler Desktop-Konverter für Karten-, POI- und Höhendaten.'
    )
    $html = [Text.RegularExpressions.Regex]::Replace($html, '"softwareVersion":"[^"]+"', '"softwareVersion":"' + $Version + '"')
    $html = [Text.RegularExpressions.Regex]::Replace($html, '"dateModified":"[^"]+"', '"dateModified":"2026-09-01"')
    $html = [Text.RegularExpressions.Regex]::Replace($html, 'v=\d+[a-z]?', "v=$cacheToken")
    [IO.File]::WriteAllText($page, $html, $utf8NoBom)
}

$sitemap = Join-Path $WebsiteRoot 'sitemap.xml'
if (Test-Path -LiteralPath $sitemap) {
    $xml = [IO.File]::ReadAllText($sitemap).Replace('<lastmod>2026-08-31</lastmod>', '<lastmod>2026-09-01</lastmod>')
    [IO.File]::WriteAllText($sitemap, $xml, $utf8NoBom)
}

Write-Host "Synchronized $($indexPages.Count) homepages, $($changelogPages.Count) changelog pages and release $Version ($ReleaseDate)."
