name: Deploy Production

on:
  push:
    branches:
      - master
  workflow_dispatch:

concurrency:
  group: production
  cancel-in-progress: false

permissions:
  contents: read
  packages: write

env:
  REGISTRY: ghcr.io
  NEXT_PUBLIC_API_URL: /api/v1
  NEXT_API_PROXY_TARGET: http://server:3001

jobs:
  build-push-deploy:
    name: Build, push, deploy, verify
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Prepare image metadata
        id: meta
        shell: bash
        run: |
          repo_lc="${GITHUB_REPOSITORY,,}"
          build_time="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
          echo "repo_lc=${repo_lc}" >> "$GITHUB_OUTPUT"
          echo "build_time=${build_time}" >> "$GITHUB_OUTPUT"
          echo "web_image=${REGISTRY}/${repo_lc}/web:${GITHUB_SHA}" >> "$GITHUB_OUTPUT"
          echo "server_image=${REGISTRY}/${repo_lc}/server:${GITHUB_SHA}" >> "$GITHUB_OUTPUT"
          echo "web_image_master=${REGISTRY}/${repo_lc}/web:master" >> "$GITHUB_OUTPUT"
          echo "server_image_master=${REGISTRY}/${repo_lc}/server:master" >> "$GITHUB_OUTPUT"

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to GHCR
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push web image
        uses: docker/build-push-action@v6
        with:
          context: .
          file: ./Dockerfile.web
          push: true
          tags: |
            ${{ steps.meta.outputs.web_image }}
            ${{ steps.meta.outputs.web_image_master }}
          build-args: |
            NEXT_PUBLIC_API_URL=${{ env.NEXT_PUBLIC_API_URL }}
            NEXT_API_PROXY_TARGET=${{ env.NEXT_API_PROXY_TARGET }}
            APP_VERSION=${{ github.sha }}
            APP_BUILD_TIME=${{ steps.meta.outputs.build_time }}
            APP_IMAGE_TAG=${{ steps.meta.outputs.web_image }}

      - name: Build and push server image
        uses: docker/build-push-action@v6
        with:
          context: .
          file: ./Dockerfile.server
          push: true
          tags: |
            ${{ steps.meta.outputs.server_image }}
            ${{ steps.meta.outputs.server_image_master }}
          build-args: |
            APP_VERSION=${{ github.sha }}
            APP_BUILD_TIME=${{ steps.meta.outputs.build_time }}
            APP_IMAGE_TAG=${{ steps.meta.outputs.server_image }}

      - name: Deploy over SSH
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.PROD_HOST }}
          username: ${{ secrets.PROD_USER }}
          key: ${{ secrets.PROD_SSH_KEY }}
          script_stop: true
          script: |
            set -euo pipefail

            cd "${{ secrets.PROD_APP_DIR }}"
            test -f .env.production

            git fetch origin master
            git checkout master
            git pull --ff-only origin master

            set_env() {
              key="$1"
              value="$2"
              if grep -q "^${key}=" .env.production; then
                sed -i "s|^${key}=.*|${key}=${value}|" .env.production
              else
                printf "\n%s=%s\n" "${key}" "${value}" >> .env.production
              fi
            }

            set_env APP_VERSION "${{ github.sha }}"
            set_env APP_BUILD_TIME "${{ steps.meta.outputs.build_time }}"
            set_env WEB_IMAGE "${{ steps.meta.outputs.web_image }}"
            set_env SERVER_IMAGE "${{ steps.meta.outputs.server_image }}"

            if [ -n "${{ secrets.GHCR_READ_TOKEN }}" ]; then
              echo "${{ secrets.GHCR_READ_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
            fi

            docker compose --env-file .env.production -f docker-compose.prod.yml pull web server
            docker compose --env-file .env.production -f docker-compose.prod.yml up -d postgres redis
            docker compose --env-file .env.production -f docker-compose.prod.yml run --rm -T server pnpm --filter server db:deploy
            docker compose --env-file .env.production -f docker-compose.prod.yml up -d --remove-orphans

            for attempt in $(seq 1 30); do
              if docker compose --env-file .env.production -f docker-compose.prod.yml exec -T web node scripts/smoke-test-release.mjs --base-url http://nginx --expected-version "${{ github.sha }}"; then
                exit 0
              fi
              sleep 2
            done

            echo "Release smoke check failed after retries"
            exit 1
