name: CD

# Continuous deployment: on every push (merge) to master:
#   1. SSH to the prod host and run deploy.sh (git pull + docker compose build/up).
#   2. Publish @lightupai/polaris to npm if the version in package.json has been
#      bumped beyond what is already published (i.e. only when there are client-side
#      changes that warrant a release).
#
# Required repository secrets (Settings → Secrets and variables → Actions):
#   DEPLOY_HOST     — hostname or IP of the prod box (e.g. polaris.lightup.ai)
#   DEPLOY_SSH_KEY  — private SSH key (OpenSSH format) for the deploy user
#   NPM_TOKEN       — npm Automation token (bypasses OTP; create at npmjs.com)
#
# Optional repository secrets (deploy.sh has sensible defaults):
#   DEPLOY_USER     — SSH user on the prod box (default: deploy)
#   DEPLOY_DIR      — checkout directory on the prod box (default: /opt/polaris)
#
# If DEPLOY_HOST / DEPLOY_SSH_KEY are not configured, the deploy job is
# skipped cleanly (check-secrets still succeeds), so this workflow is a
# safe no-op on forks and on repos where CD has not been set up yet.

on:
  push:
    branches: [master]
  workflow_dispatch:

# Never run two deploys at once; queue (don't cancel) an in-flight deploy.
concurrency:
  group: deploy-prod
  cancel-in-progress: false

jobs:
  check-secrets:
    runs-on: ubuntu-latest
    outputs:
      configured: ${{ steps.check.outputs.configured }}
    steps:
      # Secrets are not directly readable in a job-level `if`, so expose a
      # boolean output here and gate the deploy job on it.
      - name: Check deploy secrets
        id: check
        env:
          DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
          DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
        run: |
          if [ -n "$DEPLOY_HOST" ] && [ -n "$DEPLOY_SSH_KEY" ]; then
            echo "configured=true" >> "$GITHUB_OUTPUT"
            echo "Deploy secrets present — deploy job will run."
          else
            echo "configured=false" >> "$GITHUB_OUTPUT"
            echo "DEPLOY_HOST / DEPLOY_SSH_KEY not configured — skipping deploy."
          fi

  deploy:
    needs: check-secrets
    if: needs.check-secrets.outputs.configured == 'true'
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up SSH
        env:
          DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
        run: |
          mkdir -p ~/.ssh
          printf '%s\n' "$DEPLOY_SSH_KEY" > ~/.ssh/id_deploy
          chmod 600 ~/.ssh/id_deploy
          {
            echo "Host *"
            echo "  IdentityFile ~/.ssh/id_deploy"
            echo "  StrictHostKeyChecking accept-new"
          } >> ~/.ssh/config
          chmod 600 ~/.ssh/config

      - name: Deploy
        env:
          DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
          DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
          DEPLOY_DIR: ${{ secrets.DEPLOY_DIR }}
        run: ./deploy.sh

  publish-npm:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          registry-url: 'https://registry.npmjs.org'

      - name: Check if version needs publishing
        id: version-check
        run: |
          LOCAL=$(node -p "require('./package.json').version")
          PUBLISHED=$(npm view @lightupai/polaris version 2>/dev/null || echo "0.0.0")
          echo "local=$LOCAL" >> "$GITHUB_OUTPUT"
          echo "published=$PUBLISHED" >> "$GITHUB_OUTPUT"
          if [ "$LOCAL" != "$PUBLISHED" ]; then
            echo "should_publish=true" >> "$GITHUB_OUTPUT"
            echo "Version $LOCAL differs from published $PUBLISHED — will publish."
          else
            echo "should_publish=false" >> "$GITHUB_OUTPUT"
            echo "Version $LOCAL already published — skipping npm publish."
          fi

      - name: Publish to npm
        if: steps.version-check.outputs.should_publish == 'true'
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: |
          npm publish --access public || {
            # If publish failed (E403 = already published, E409 = staged/in-flight),
            # retry npm view a few times to let propagation settle, then treat as success.
            for i in 1 2 3; do
              sleep 5
              if npm view @lightupai/polaris@${{ steps.version-check.outputs.local }} version > /dev/null 2>&1; then
                echo "Version ${{ steps.version-check.outputs.local }} already published — skipping (race condition, attempt $i)."
                exit 0
              fi
            done
            exit 1
          }
