name: CI | Publish cyberia npm package
on:
  push:
    tags:
      - 'v*'
permissions:
  contents: write
  packages: write
  id-token: write
jobs:
  build-and-publish:
    # The unscoped `cyberia` package has one publisher: a version can be published once, and the
    # organization mirror publishes the owner-scoped package from its ghpkg repository.
    if: (github.repository == 'underpostnet/engine-cyberia' || github.repository == 'underpost/engine-cyberia')
    runs-on: ubuntu-latest
    permissions:
      contents: write
      packages: write
      id-token: write
    steps:
      - uses: actions/checkout@v7

      - name: Install required packages
        run: |
          sudo apt-get update -y
          sudo apt-get install -y sudo tar gzip bzip2 git curl

      - uses: actions/setup-node@v7
        with:
          node-version: '24.x'
          registry-url: 'https://registry.npmjs.org'

      - name: Install Dependencies
        run: npm ci

      # The repository declares the engine's runtime dependencies because it runs the engine
      # source it ships; a registry consumer gets them through `underpost` instead. This restores
      # the manifest the package published before that split, and only in the tarball — after
      # `npm ci`, so the lockfile the checkout installs from is the repository's own.
      - name: Restore the published dependency set
        run: |
          node --input-type=module -e '
            import fs from "node:fs";
            import { publishedProductPackageJson, DEPLOY_MANIFEST_INDENT } from "./src/server/build/package.js";
            import { loadDeployCatalog } from "./src/server/build/catalog.js";
            const packageJson = JSON.parse(fs.readFileSync("./package.json", "utf8"));
            const published = publishedProductPackageJson({
              packageJson,
              catalog: await loadDeployCatalog("dd-cyberia"),
            });
            fs.writeFileSync("./package.json", JSON.stringify(published, null, DEPLOY_MANIFEST_INDENT) + "\n", "utf8");
            console.log("published manifest", {
              dependencies: Object.keys(published.dependencies).length,
              devDependencies: Object.keys(published.devDependencies ?? {}).length,
            });
          '

      # npm accepts a version once: a rerun skips the registry.
      - name: Check whether this version is already on npm
        id: npm
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: |
          NAME=$(node -p 'require("./package.json").name')
          VERSION=$(node -p 'require("./package.json").version')
          if [ "$(npm view "$NAME@$VERSION" version 2>/dev/null)" = "$VERSION" ]; then
            echo "::notice::$NAME@$VERSION is already on npm; skipping it."
            echo "published=true" >> "$GITHUB_OUTPUT"
          else
            echo "published=false" >> "$GITHUB_OUTPUT"
          fi

      - name: Publish to npm
        if: steps.npm.outputs.published != 'true'
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: npm publish --provenance --access public

  build-and-publish-ghpkg:
    # The scoped package takes the repository owner as its scope, so the personal account and the
    # organization mirror each publish their own; any other owner is a fork.
    if: >-
      github.event.repository.name == 'engine-ghpkg-cyberia' &&
      contains(fromJSON('["underpostnet","underpost"]'), github.repository_owner)
    runs-on: ubuntu-latest
    permissions:
      contents: write
      packages: write
      id-token: write
    steps:
      - uses: actions/checkout@v7

      - uses: actions/setup-node@v7
        with:
          node-version: '24.x'
          registry-url: 'https://registry.npmjs.org'
          scope: '@${{ github.repository_owner }}'

      - name: Install Dependencies
        run: npm ci

      # The committed manifest names the personal account. Provenance is refused when the
      # manifest's repository differs from the one the workflow runs in, and GitHub Packages
      # accepts only the owner's scope, so both follow the owner here — a no-op on the source.
      - name: Align the package identity with the repository owner
        run: node bin package --rename "@${{ github.repository_owner }}/cyberia" --set-repo "${{ github.repository }}"

      # The repository declares the engine's runtime dependencies because it runs the engine
      # source it ships; a registry consumer gets them through `@underpost/underpost` instead,
      # because the scoped package is what GitHub Packages resolves. This restores the manifest
      # the package published before that split, and only in the tarball — after `npm ci`, so
      # the lockfile the checkout installs from is the repository's own.
      - name: Restore the published dependency set
        run: |
          node --input-type=module -e '
            import fs from "node:fs";
            import { publishedProductPackageJson, DEPLOY_MANIFEST_INDENT } from "./src/server/build/package.js";
            import { loadDeployCatalog } from "./src/server/build/catalog.js";
            const packageJson = JSON.parse(fs.readFileSync("./package.json", "utf8"));
            const published = publishedProductPackageJson({
              packageJson,
              catalog: await loadDeployCatalog("dd-cyberia"),
              underpostPackageName: "@${{ github.repository_owner }}/underpost",
            });
            fs.writeFileSync("./package.json", JSON.stringify(published, null, DEPLOY_MANIFEST_INDENT) + "\n", "utf8");
            console.log("published manifest", {
              dependencies: Object.keys(published.dependencies).length,
              devDependencies: Object.keys(published.devDependencies ?? {}).length,
            });
          '

      # npm accepts a version once: when it is already there, go straight to GitHub Packages.
      - name: Check whether this version is already on npm
        id: npm
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: |
          NAME=$(node -p 'require("./package.json").name')
          VERSION=$(node -p 'require("./package.json").version')
          if [ "$(npm view "$NAME@$VERSION" version 2>/dev/null)" = "$VERSION" ]; then
            echo "::notice::$NAME@$VERSION is already on npm; skipping it."
            echo "published=true" >> "$GITHUB_OUTPUT"
          else
            echo "published=false" >> "$GITHUB_OUTPUT"
          fi

      - name: Publish to npm
        if: steps.npm.outputs.published != 'true'
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: npm publish --provenance --access public

      - name: Setup node to publish to GitHub Packages
        uses: actions/setup-node@v7
        with:
          node-version: '24.x'
          registry-url: 'https://npm.pkg.github.com'
          scope: '@${{ github.repository_owner }}'

      - name: Publish to GitHub Packages
        env:
          NODE_AUTH_TOKEN: ${{ secrets.GIT_AUTH_TOKEN }}
        run: |
          echo "//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}" > ~/.npmrc
          echo "@${{ github.repository_owner }}:registry=https://npm.pkg.github.com" >> ~/.npmrc
          npm publish
