name: Staging deployment

on:
  push:
    branches-ignore: [main]
  delete:
  pull_request:
    types: [opened]

jobs:
  deploy:
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    env:
      BRANCH: ${{ github.ref_name }}
    steps:
      - uses: actions/checkout@v4

      - name: Compute staging name
        run: |
          SLUG=$(echo "$BRANCH" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9-]+/-/g; s/-+/-/g; s/^-//; s/-$//' | cut -c1-40)
          echo "SLUG=${SLUG}" >> "$GITHUB_ENV"
          echo "HOST=tracker-${SLUG}.home.arpa" >> "$GITHUB_ENV"
          # Per-staging secret so each instance has its own key, decoupling it
          # from prod even though the database is seeded from a prod snapshot.
          echo "STAGING_SECRET_KEY=staging-${SLUG}-$(head -c16 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9')" >> "$GITHUB_ENV"

      - name: Build image
        run: docker build -t "timetracker:staging-${SLUG}" .

      - name: Seed database from prod (first deploy of this branch only)
        run: |
          if docker volume inspect "timetracker-staging-${SLUG}" >/dev/null 2>&1; then
            echo "Volume exists, keeping current staging data"
            exit 0
          fi
          docker volume create "timetracker-staging-${SLUG}"
          # sqlite3.backup() takes a consistent online snapshot (WAL-safe);
          # prod is only read, never written.
          docker run --rm \
            -v /docker/timetracker/data:/prod \
            -v "timetracker-staging-${SLUG}:/dest" \
            python:3.14-slim-bookworm sh -c "
              python -c \"
          import sqlite3
          source = sqlite3.connect('file:/prod/db.sqlite3?mode=ro', uri=True)
          destination = sqlite3.connect('/dest/db.sqlite3')
          source.backup(destination)
          games = destination.execute('select count(*) from games_game').fetchone()[0]
          sessions = destination.execute('select count(*) from games_session').fetchone()[0]
          print(f'Seeded staging database: {games} games, {sessions} sessions')
          destination.close()
          source.close()
          \" && chown 1000:100 /dest/db.sqlite3"

      - name: Deploy staging container
        run: |
          docker rm -f "timetracker-staging-${SLUG}" 2>/dev/null || true
          docker run -d --name "timetracker-staging-${SLUG}" \
            --network docker-compose-templates_public \
            -e TZ=Europe/Prague \
            -e PUID=1000 \
            -e PGID=100 \
            -e DATA_DIR=/home/timetracker/app/data \
            -e STAGING=true \
            -e "SECRET_KEY=${STAGING_SECRET_KEY}" \
            -e "APP_URL=https://${HOST}" \
            -v "timetracker-staging-${SLUG}:/home/timetracker/app/data" \
            -l "caddy=${HOST}" \
            -l 'caddy.reverse_proxy={{ upstreams 8000 }}' \
            -l xyz.kucharczyk.staging=timetracker \
            -l "xyz.kucharczyk.staging.branch=${BRANCH}" \
            --restart unless-stopped \
            "timetracker:staging-${SLUG}"

      - name: Summary
        run: |
          echo "Deployed to https://${HOST}"
          echo "Deployed to https://${HOST}" >> "$GITHUB_STEP_SUMMARY"

      - name: Comment staging URL on PR
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          auth="Authorization: token ${GITHUB_TOKEN}"
          api="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}"
          pr=$(curl -fsS -H "$auth" "${api}/pulls?state=open&limit=50" \
            | jq -r --arg branch "$BRANCH" '.[] | select(.head.ref == $branch) | .number' | head -n1)
          if [ -z "$pr" ]; then
            echo "No open PR for branch '${BRANCH}', skipping comment"
            exit 0
          fi
          body="Staging deployment: https://${HOST}"
          if curl -fsS -H "$auth" "${api}/issues/${pr}/comments" \
            | jq -e --arg body "$body" 'any(.[]; .body == $body)' >/dev/null; then
            echo "Staging URL already commented on PR #${pr}"
            exit 0
          fi
          curl -fsS -X POST -H "$auth" -H 'Content-Type: application/json' \
            -d "$(jq -n --arg body "$body" '{body: $body}')" \
            "${api}/issues/${pr}/comments" >/dev/null
          echo "Commented staging URL on PR #${pr}"

  comment:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    env:
      BRANCH: ${{ github.event.pull_request.head.ref }}
      PR: ${{ github.event.pull_request.number }}
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - name: Comment staging URL on the new PR
        run: |
          SLUG=$(echo "$BRANCH" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9-]+/-/g; s/-+/-/g; s/^-//; s/-$//' | cut -c1-40)
          HOST="tracker-${SLUG}.home.arpa"
          auth="Authorization: token ${GITHUB_TOKEN}"
          api="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}"
          body="Staging deployment: https://${HOST}"
          if curl -fsS -H "$auth" "${api}/issues/${PR}/comments" \
            | jq -e --arg body "$body" 'any(.[]; .body == $body)' >/dev/null; then
            echo "Staging URL already commented on PR #${PR}"
            exit 0
          fi
          curl -fsS -X POST -H "$auth" -H 'Content-Type: application/json' \
            -d "$(jq -n --arg body "$body" '{body: $body}')" \
            "${api}/issues/${PR}/comments" >/dev/null
          echo "Commented staging URL on PR #${PR}"

  teardown:
    if: github.event_name == 'delete' && github.event.ref_type == 'branch'
    runs-on: ubuntu-latest
    env:
      BRANCH: ${{ github.event.ref }}
    steps:
      - name: Remove staging container, volume, and image
        run: |
          SLUG=$(echo "$BRANCH" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9-]+/-/g; s/-+/-/g; s/^-//; s/-$//' | cut -c1-40)
          docker rm -f "timetracker-staging-${SLUG}" 2>/dev/null || true
          docker volume rm "timetracker-staging-${SLUG}" 2>/dev/null || true
          docker rmi "timetracker:staging-${SLUG}" 2>/dev/null || true
