name: PLONDS

on:
  release:
    types:
      - published
      - prereleased
  workflow_dispatch:
    inputs:
      tag:
        description: 'Release tag'
        required: true
        type: string
      baseline_tag:
        description: 'Optional baseline tag'
        required: false
        type: string
      channel:
        description: 'Update channel'
        required: false
        type: choice
        default: stable
        options:
          - stable
          - preview

env:
  DOTNET_VERSION: '10.0.x'

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: write

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          submodules: recursive

      - name: Resolve release context
        shell: bash
        run: |
          if [[ "${{ github.event_name }}" == "release" ]]; then
            TAG="${{ github.event.release.tag_name }}"
            if [[ "${{ github.event.release.prerelease }}" == "true" ]]; then
              CHANNEL="preview"
            else
              CHANNEL="stable"
            fi
            BASELINE_TAG=""
          else
            RAW_TAG="${{ github.event.inputs.tag }}"
            if [[ "${RAW_TAG}" == v* ]]; then
              TAG="${RAW_TAG}"
            else
              TAG="v${RAW_TAG}"
            fi
            CHANNEL="${{ github.event.inputs.channel }}"
            BASELINE_TAG="${{ github.event.inputs.baseline_tag }}"
          fi

          echo "RELEASE_TAG=${TAG}" >> "$GITHUB_ENV"
          echo "RELEASE_VERSION=${TAG#v}" >> "$GITHUB_ENV"
          echo "RELEASE_CHANNEL=${CHANNEL}" >> "$GITHUB_ENV"
          echo "BASELINE_TAG_INPUT=${BASELINE_TAG}" >> "$GITHUB_ENV"

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ env.DOTNET_VERSION }}
          dotnet-quality: preview

      - name: Prepare signing key
        env:
          UPDATE_PRIVATE_KEY_PEM: ${{ secrets.UPDATE_PRIVATE_KEY_PEM }}
          PLONDS_SIGNING_KEY: ${{ secrets.PLONDS_SIGNING_KEY }}
          PDC_SIGNING_KEY: ${{ secrets.PDC_SIGNING_KEY }}
        shell: bash
        run: |
          set -euo pipefail
          KEY="${PLONDS_SIGNING_KEY:-}"
          if [[ -z "$KEY" ]]; then KEY="${UPDATE_PRIVATE_KEY_PEM:-}"; fi
          if [[ -z "$KEY" ]]; then KEY="${PDC_SIGNING_KEY:-}"; fi
          if [[ -z "$KEY" ]]; then
            echo "No signing key is configured."
            exit 1
          fi
          printf '%s' "$KEY" > update-private-key.pem
          echo "UPDATE_PRIVATE_KEY_PATH=$PWD/update-private-key.pem" >> "$GITHUB_ENV"

      - name: Build PLONDS tool
        run: dotnet build PenguinLogisticsOnlineNetworkDistributionSystem/src/Plonds.Tool/Plonds.Tool.csproj -c Release

      - name: Resolve baseline plan
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        shell: pwsh
        run: |
          $ErrorActionPreference = 'Stop'
          $repo = '${{ github.repository }}'
          $tag = $env:RELEASE_TAG
          $baselineInput = $env:BASELINE_TAG_INPUT
          $currentRelease = gh release view $tag --repo $repo --json tagName,isPrerelease,assets,publishedAt | ConvertFrom-Json
          $allReleases = gh api "repos/$repo/releases?per_page=100" | ConvertFrom-Json
          $platforms = @('windows-x64', 'windows-x86', 'linux-x64')

          $entries = foreach ($platform in $platforms) {
            $assetName = "files-$platform.zip"
            $currentAsset = $currentRelease.assets | Where-Object { $_.name -eq $assetName } | Select-Object -First 1
            if (-not $currentAsset) {
              throw "Current release $tag does not contain required asset $assetName"
            }

            $baselineRelease = $null
            if (-not [string]::IsNullOrWhiteSpace($baselineInput)) {
              $normalizedBaseline = if ($baselineInput.StartsWith('v')) { $baselineInput } else { "v$baselineInput" }
              $baselineRelease = $allReleases | Where-Object { $_.tag_name -eq $normalizedBaseline } | Select-Object -First 1
              if (-not $baselineRelease) {
                throw "Specified baseline tag not found: $normalizedBaseline"
              }
            }
            else {
              $baselineRelease = $allReleases |
                Where-Object {
                  $_.tag_name -ne $tag -and
                  -not $_.draft -and
                  [bool]$_.prerelease -eq [bool]$currentRelease.isPrerelease -and
                  ($_.assets | Where-Object { $_.name -eq $assetName } | Measure-Object).Count -gt 0
                } |
                Select-Object -First 1
            }

            [pscustomobject]@{
              platform = $platform
              assetName = $assetName
              baselineTag = if ($baselineRelease) { $baselineRelease.tag_name } else { $null }
              baselineVersion = if ($baselineRelease) { ($baselineRelease.tag_name -replace '^v', '') } else { $null }
              isFullPayload = -not $baselineRelease
            }
          }

          $plan = [pscustomobject]@{
            tag = $tag
            version = $env:RELEASE_VERSION
            channel = $env:RELEASE_CHANNEL
            platforms = $entries
          }

          $plan | ConvertTo-Json -Depth 8 | Set-Content plonds-plan.json -Encoding utf8
          Get-Content plonds-plan.json

      - name: Download payload zips
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        shell: pwsh
        run: |
          $ErrorActionPreference = 'Stop'
          $repo = '${{ github.repository }}'
          $plan = Get-Content plonds-plan.json | ConvertFrom-Json

          foreach ($entry in $plan.platforms) {
            $currentDir = Join-Path $PWD "plonds-input/current/$($entry.platform)"
            New-Item -ItemType Directory -Path $currentDir -Force | Out-Null
            gh release download $plan.tag --repo $repo -p $entry.assetName -D $currentDir

            if (-not [string]::IsNullOrWhiteSpace($entry.baselineTag)) {
              $baselineDir = Join-Path $PWD "plonds-input/baseline/$($entry.platform)"
              New-Item -ItemType Directory -Path $baselineDir -Force | Out-Null
              gh release download $entry.baselineTag --repo $repo -p $entry.assetName -D $baselineDir
            }
          }

      - name: Build delta assets
        shell: pwsh
        run: |
          $ErrorActionPreference = 'Stop'
          $plan = Get-Content plonds-plan.json | ConvertFrom-Json
          foreach ($entry in $plan.platforms) {
            $currentZip = Join-Path $PWD "plonds-input/current/$($entry.platform)/$($entry.assetName)"
            $args = @(
              'run', '--project', 'PenguinLogisticsOnlineNetworkDistributionSystem/src/Plonds.Tool/Plonds.Tool.csproj', '--configuration', 'Release', '--',
              'build-delta',
              '--platform', $entry.platform,
              '--current-version', $plan.version,
              '--current-tag', $plan.tag,
              '--current-zip', $currentZip,
              '--output-dir', 'plonds-output',
              '--private-key', $env:UPDATE_PRIVATE_KEY_PATH,
              '--channel', $plan.channel
            )

            if ([bool]$entry.isFullPayload) {
              $args += @('--is-full-payload', 'true')
            }
            else {
              $baselineZip = Join-Path $PWD "plonds-input/baseline/$($entry.platform)/$($entry.assetName)"
              $args += @('--baseline-tag', $entry.baselineTag, '--baseline-version', $entry.baselineVersion, '--baseline-zip', $baselineZip)
            }

            dotnet @args
          }

          dotnet run --project PenguinLogisticsOnlineNetworkDistributionSystem/src/Plonds.Tool/Plonds.Tool.csproj --configuration Release -- `
            build-index `
            --release-tag $plan.tag `
            --version $plan.version `
            --channel $plan.channel `
            --platform-summaries-dir plonds-output/platform-summaries `
            --output-dir plonds-output `
            --private-key $env:UPDATE_PRIVATE_KEY_PATH

      - name: Upload PLONDS assets to release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        shell: bash
        run: |
          set -euo pipefail
          gh release upload "$RELEASE_TAG" plonds-output/release-assets/* --clobber

      - name: Persist run metadata
        shell: bash
        run: |
          mkdir -p plonds-run-metadata
          printf '%s' "$RELEASE_TAG" > plonds-run-metadata/tag.txt

      - name: Upload run metadata artifact
        uses: actions/upload-artifact@v4
        with:
          name: plonds-run-metadata
          path: plonds-run-metadata/tag.txt
          if-no-files-found: error
          retention-days: 7
