name: Database Backup
run-name: 💾 DB Backup triggered by @${{ gitea.actor }}

# ───────────────────────────────────────────────────────
# Owner: DevOps (Architekt)
# Trigger: Manual (workflow_dispatch) + optional schedule.
#
# Strategy:
#   1. Connects to the live PostgreSQL container via docker exec.
#   2. Runs pg_dumpall (full cluster dump, single file).
#   3. Compresses with gzip.
#   4. Uploads as a Gitea Action artifact (or writes to host path).
#   5. Artifacts are retained per Gitea repo settings (default 90 days).
#
# Rotation: Gitea artifact expiration handles old backups automatically.
#   For longer retention, configure an external cron job or use the
#   host_path output to copy the backup elsewhere.
#
# Restoration: See phases/deployment.md for step-by-step instructions.
# ───────────────────────────────────────────────────────
concurrency:
  group: db-backup
  cancel-in-progress: false

on:
  workflow_dispatch:
    inputs:
      keep_on_host:
        description: 'Also copy backup to host path?'
        required: false
        default: false
        type: boolean
      host_backup_path:
        description: 'Host path for backup (only if keep_on_host is true)'
        required: false
        default: '/home/projekte_bao/backups/nexus'
        type: string

  # Optional: uncomment to enable nightly automatic backups
  # schedule:
  #   - cron: '0 3 * * *'  # Every night at 03:00 UTC

jobs:
  backup:
    name: Backup PostgreSQL
    runs-on: linux
    env:
      ENV_TMPFILE: /tmp/nexus-backup-env
      ENV_POSTGRES_PASSWORD: ${{ secrets.ENV_POSTGRES_PASSWORD }}
      DEPLOY_PATH: /home/projekte_bao/nexus
      BACKUP_CONTAINER_NAME: nexus-postgres-1

    steps:
      # ═══════════════════════════════════════════════════
      # Step 1: Generate backup filename
      # ═══════════════════════════════════════════════════
      - name: Generate backup identifier
        id: meta
        run: |
          TIMESTAMP=$(date -u +'%Y-%m-%dT%H%M%SZ')
          echo "timestamp=${TIMESTAMP}" >> "$GITEA_OUTPUT"
          echo "filename=nexus-backup-${TIMESTAMP}.sql.gz" >> "$GITEA_OUTPUT"
          echo "📅 Backup ID: ${TIMESTAMP}"

      # ═══════════════════════════════════════════════════
      # Step 2: Dump PostgreSQL via docker exec
      # ═══════════════════════════════════════════════════
      - name: Dump database
        run: |
          set -euo pipefail

          echo "🗄️  Dumping PostgreSQL cluster..."

          docker exec "${BACKUP_CONTAINER_NAME}" \
            sh -c "PGPASSWORD='${ENV_POSTGRES_PASSWORD}' pg_dumpall -U nexus" \
            | gzip > "${{ steps.meta.outputs.filename }}"

          SIZE=$(du -h "${{ steps.meta.outputs.filename }}" | cut -f1)
          echo "✅ Backup written: ${{ steps.meta.outputs.filename }} (${SIZE})"

      # ═══════════════════════════════════════════════════
      # Step 3: Upload backup as Gitea artifact
      # ═══════════════════════════════════════════════════
      - name: Upload backup artifact
        uses: actions/upload-artifact@v4
        with:
          name: nexus-backup-${{ steps.meta.outputs.timestamp }}
          path: ${{ steps.meta.outputs.filename }}
          retention-days: 90
          compression-level: 0  # already gzipped

      # ═══════════════════════════════════════════════════
      # Step 4: Optional — copy to host filesystem
      # ═══════════════════════════════════════════════════
      - name: Copy backup to host (optional)
        if: inputs.keep_on_host == true
        run: |
          set -euo pipefail

          HOST_PATH="${{ inputs.host_backup_path }}"

          # Create host dir if it doesn't exist
          docker run --rm \
            -v "${HOST_PATH}:/backup-target" \
            -v "${{ gitea.workspace }}:/src:ro" \
            alpine:latest \
            sh -c "
              mkdir -p /backup-target && \
              cp /src/${{ steps.meta.outputs.filename }} /backup-target/ && \
              echo '✅ Backup copied to host: ${HOST_PATH}/${{ steps.meta.outputs.filename }}'
            "

      # ═══════════════════════════════════════════════════
      # Step 5: Verify backup integrity
      # ═══════════════════════════════════════════════════
      - name: Verify backup integrity
        run: |
          echo "🔍 Verifying backup integrity..."
          if gzip -t "${{ steps.meta.outputs.filename }}"; then
            echo "✅ Backup gzip integrity check passed"
          else
            echo "❌ Backup file is corrupted!"
            exit 1
          fi

          # Quick content check: should start with PostgreSQL dump header
          HEADER=$(zcat "${{ steps.meta.outputs.filename }}" | head -1)
          if echo "$HEADER" | grep -qE '^(-- PostgreSQL database cluster dump|-- Dumped|--)'; then
            echo "✅ Backup content header check passed"
          else
            echo "⚠️  Unexpected backup header (may still be valid): $HEADER"
          fi

      # ═══════════════════════════════════════════════════
      # Step 6: Backup Summary
      # ═══════════════════════════════════════════════════
      - name: Backup Summary
        if: always()
        run: |
          STATUS="${{ job.status }}"
          echo ""
          echo "═══════════════════════════════════════"
          echo "  💾 Database Backup Summary"
          echo "═══════════════════════════════════════"
          echo "  File:        ${{ steps.meta.outputs.filename }}"
          echo "  Timestamp:   ${{ steps.meta.outputs.timestamp }}"
          echo "  Triggered:   @${{ gitea.actor }}"
          echo "  On host:     ${{ inputs.keep_on_host == 'true' && inputs.host_backup_path || 'No (artifact only)' }}"
          echo "  Status:      ${STATUS}"
          echo "═══════════════════════════════════════"

          if [ "${STATUS}" = "success" ]; then
            echo ""
            echo "💡 Restore command (manual, on host):"
            echo "   zcat ${{ steps.meta.outputs.filename }} | docker exec -i nexus-postgres-1 psql -U nexus -d postgres"
          fi
