name: Queue Release Build

on:
  push:
    branches: [main, master]
  workflow_dispatch:

jobs:
  prepare:
    runs-on: ubuntu-latest
    container: node:22

    outputs:
      release_tag: ${{ steps.version.outputs.release_tag }}
      release_name: ${{ steps.version.outputs.release_name }}
      release_version: ${{ steps.version.outputs.release_version }}
      release_id: ${{ steps.release.outputs.release_id }}
      release_download_url: ${{ steps.release.outputs.release_download_url }}

    steps:
      - name: Checkout
        uses: https://github.com/actions/checkout@v4

      - name: Resolve release version
        id: version
        run: node tools/resolve-release-version.js --write-output

      - name: Ensure draft release exists
        id: release
        env:
          GITEA_RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
        run: >
          node tools/gitea-release.js ensure-draft
          --server-url "${{ github.server_url }}"
          --repository "${{ github.repository }}"
          --tag "${{ steps.version.outputs.release_tag }}"
          --target "${{ github.sha }}"
          --name "${{ steps.version.outputs.release_name }}"
          --body "Automated draft release from ${{ github.ref_name }} @ ${{ github.sha }}"
          --write-output

  build-linux:
    needs: prepare
    runs-on: ubuntu-latest
    container: node:22

    steps:
      - name: Checkout
        uses: https://github.com/actions/checkout@v4

      - name: Restore npm cache
        uses: https://github.com/actions/cache@v4
        with:
          path: /root/.npm
          key: npm-linux-${{ hashFiles('package-lock.json', 'server/package-lock.json', 'docs-site/package-lock.json') }}
          restore-keys: npm-linux-

      - name: Restore Electron cache
        uses: https://github.com/actions/cache@v4
        with:
          path: |
            /root/.cache/electron
            /root/.cache/electron-builder
          key: electron-linux-${{ hashFiles('package.json') }}
          restore-keys: electron-linux-

      - name: Install dependencies
        env:
          NODE_ENV: development
        run: |
          apt-get update && apt-get install -y --no-install-recommends zip
          npm ci
          cd server && npm ci
          cd ../docs-site && npm ci

      - name: Set CI release version
        run: >
          node tools/set-release-version.js
          --version "${{ needs.prepare.outputs.release_version }}"

      - name: Build application
        run: |
          npx esbuild node_modules/@timephy/rnnoise-wasm/dist/NoiseSuppressorWorklet.js --bundle --format=esm --outfile=toju-app/public/rnnoise-worklet.js
          cd toju-app
          npx ng build --configuration production --base-href='./'
          cd ..
          npm run build:docs
          npx --package typescript tsc -p tsconfig.electron.json
          cd server
          node ../tools/sync-server-build-version.js
          npx --package typescript tsc

      - name: Build Linux assets
        run: |
          npx electron-builder --linux --publish never
          node tools/package-server-executable.js --target node18-linux-x64 --output metoyou-server-linux-x64
          rm -f dist-electron/metoyou-client-${{ needs.prepare.outputs.release_version }}.zip
          rm -f dist-server/metoyou-server-linux-x64-${{ needs.prepare.outputs.release_version }}.zip
          (cd dist && zip -rq ../dist-electron/metoyou-client-${{ needs.prepare.outputs.release_version }}.zip client)
          (cd dist-server && zip -q metoyou-server-linux-x64-${{ needs.prepare.outputs.release_version }}.zip metoyou-server-linux-x64 sql-wasm.wasm)

      - name: Upload Linux assets
        env:
          GITEA_RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
        run: >
          node tools/gitea-release.js upload-built-assets
          --server-url "${{ github.server_url }}"
          --repository "${{ github.repository }}"
          --release-id "${{ needs.prepare.outputs.release_id }}"
          --dist-electron dist-electron
          --dist-server dist-server

  build-windows:
    needs: prepare
    runs-on: windows

    defaults:
      run:
        shell: powershell

    steps:
      - name: Checkout
        uses: https://github.com/actions/checkout@v4

      - name: Restore npm cache
        uses: https://github.com/actions/cache@v4
        with:
          path: ~/AppData/Local/npm-cache
          key: npm-windows-${{ hashFiles('package-lock.json', 'server/package-lock.json', 'docs-site/package-lock.json') }}
          restore-keys: npm-windows-

      - name: Restore Electron cache
        uses: https://github.com/actions/cache@v4
        with:
          path: |
            ~/AppData/Local/electron/Cache
            ~/AppData/Local/electron-builder/Cache
          key: electron-windows-${{ hashFiles('package.json') }}
          restore-keys: electron-windows-

      - name: Install dependencies
        env:
          NODE_ENV: development
        run: |
          npm ci
          npm ci --prefix server
          npm ci --prefix docs-site

      - name: Set CI release version
        run: >
          node tools/set-release-version.js
          --version "${{ needs.prepare.outputs.release_version }}"

      - name: Build application
        run: |
          npx esbuild node_modules/@timephy/rnnoise-wasm/dist/NoiseSuppressorWorklet.js --bundle --format=esm --outfile=toju-app/public/rnnoise-worklet.js
          Push-Location "toju-app"
          npx ng build --configuration production --base-href='./'
          Pop-Location
          npm run build:docs
          npx --package typescript tsc -p tsconfig.electron.json
          Push-Location server
          node ../tools/sync-server-build-version.js
          npx --package typescript tsc
          Pop-Location

      - name: Build Windows assets
        run: |
          $projectRoot = $PWD.ProviderPath
          $electronBuilderWorkspace = Join-Path $env:TEMP ([guid]::NewGuid().ToString('N'))
          $electronBuilderCache = Join-Path $electronBuilderWorkspace 'electron-builder-cache'
          $electronCache = Join-Path $electronBuilderWorkspace 'electron-cache'
          $locationPushed = $false

          function Invoke-RoboCopy {
            param(
              [string]$Source,
              [string]$Destination
            )

            robocopy $Source $Destination /MIR /NFL /NDL /NJH /NJS /NP | Out-Null

            if ($LASTEXITCODE -gt 7) {
              throw "robocopy failed from $Source to $Destination with exit code $LASTEXITCODE"
            }
          }

          # Stage the packaging inputs into a real short-path directory.
          # electron-builder rejects junction-backed files during asar creation
          # because their resolved path sits outside the package root.
          New-Item -ItemType Directory -Path $electronBuilderWorkspace | Out-Null
          New-Item -ItemType Directory -Path $electronBuilderCache | Out-Null
          New-Item -ItemType Directory -Path $electronCache | Out-Null
          $env:ELECTRON_BUILDER_CACHE = $electronBuilderCache
          $env:ELECTRON_CACHE = $electronCache

          try {
            Copy-Item -Path (Join-Path $projectRoot 'package.json') -Destination (Join-Path $electronBuilderWorkspace 'package.json') -Force
            Copy-Item -Path (Join-Path $projectRoot 'package-lock.json') -Destination (Join-Path $electronBuilderWorkspace 'package-lock.json') -Force
            Invoke-RoboCopy (Join-Path $projectRoot 'dist') (Join-Path $electronBuilderWorkspace 'dist')
            Invoke-RoboCopy (Join-Path $projectRoot 'docs-site/build') (Join-Path $electronBuilderWorkspace 'docs-site/build')
            Invoke-RoboCopy (Join-Path $projectRoot 'images') (Join-Path $electronBuilderWorkspace 'images')
            Invoke-RoboCopy (Join-Path $projectRoot 'node_modules') (Join-Path $electronBuilderWorkspace 'node_modules')

            Push-Location $electronBuilderWorkspace
            $locationPushed = $true
            npx electron-builder --win --publish never
            if ($LASTEXITCODE -ne 0) {
              throw "electron-builder failed with exit code $LASTEXITCODE"
            }

            Invoke-RoboCopy (Join-Path $electronBuilderWorkspace 'dist-electron') (Join-Path $projectRoot 'dist-electron')
          } finally {
            if ($locationPushed) {
              Pop-Location
            }
            if (Test-Path $electronBuilderWorkspace) {
              cmd /c rmdir /s /q "$electronBuilderWorkspace" | Out-Null
            }
          }
          node tools/package-server-executable.js --target node18-win-x64 --output metoyou-server-win-x64.exe
          $serverArchivePath = Join-Path $PWD "dist-server/metoyou-server-win-x64-${{ needs.prepare.outputs.release_version }}.zip"
          if (Test-Path $serverArchivePath) {
            Remove-Item $serverArchivePath -Force
          }
          Push-Location dist-server
          try {
            Compress-Archive -Path metoyou-server-win-x64.exe, sql-wasm.wasm -DestinationPath $serverArchivePath -CompressionLevel Optimal
          } finally {
            Pop-Location
          }

      - name: Upload Windows assets
        env:
          GITEA_RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
        run: >
          node tools/gitea-release.js upload-built-assets
          --server-url "${{ github.server_url }}"
          --repository "${{ github.repository }}"
          --release-id "${{ needs.prepare.outputs.release_id }}"
          --dist-electron dist-electron
          --dist-server dist-server

  finalize:
    needs: [prepare, build-linux, build-windows]
    runs-on: ubuntu-latest
    container: node:22

    steps:
      - name: Checkout
        uses: https://github.com/actions/checkout@v4

      - name: Download previous manifest
        env:
          GITEA_RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
        run: >
          node tools/gitea-release.js download-latest-manifest
          --server-url "${{ github.server_url }}"
          --repository "${{ github.repository }}"
          --output dist-electron/release-manifest.previous.json
          --allow-missing

      - name: Generate release manifest
        run: >
          node tools/generate-release-manifest.js
          --existing dist-electron/release-manifest.previous.json
          --manifest dist-electron/release-manifest.json
          --feed-url "${{ needs.prepare.outputs.release_download_url }}"
          --version "${{ needs.prepare.outputs.release_version }}"

      - name: Upload release manifest
        env:
          GITEA_RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
        run: >
          node tools/gitea-release.js upload-built-assets
          --server-url "${{ github.server_url }}"
          --repository "${{ github.repository }}"
          --release-id "${{ needs.prepare.outputs.release_id }}"
          --dist-electron dist-electron
          --dist-server dist-server
