name: Docker Build, Publish & Test

on:
  push:
    branches:
      - main
      - development
      - feature/beta-release
    # Note: Tags are handled by release-goreleaser.yml to avoid duplicate builds
  pull_request:
    branches:
      - main
      - development
      - feature/beta-release
  workflow_dispatch:
  workflow_call:

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository_owner }}/charon

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    permissions:
      contents: read
      packages: write
      security-events: write

    outputs:
      skip_build: ${{ steps.skip.outputs.skip_build }}
      digest: ${{ steps.build-and-push.outputs.digest }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6

      - name: Normalize image name
        run: |
          echo "IMAGE_NAME=$(echo "${{ env.IMAGE_NAME }}" | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV

      - name: Determine skip condition
        id: skip
        env:
          ACTOR: ${{ github.actor }}
          EVENT: ${{ github.event_name }}
          HEAD_MSG: ${{ github.event.head_commit.message }}
          REF: ${{ github.ref }}
        run: |
          should_skip=false
          pr_title=""
          if [ "$EVENT" = "pull_request" ]; then
            pr_title=$(jq -r '.pull_request.title' "$GITHUB_EVENT_PATH" 2>/dev/null || echo '')
          fi
          if [ "$ACTOR" = "renovate[bot]" ]; then should_skip=true; fi
          if echo "$HEAD_MSG" | grep -Ei '^chore\(deps' >/dev/null 2>&1; then should_skip=true; fi
          if echo "$HEAD_MSG" | grep -Ei '^chore:' >/dev/null 2>&1; then should_skip=true; fi
          if echo "$pr_title" | grep -Ei '^chore\(deps' >/dev/null 2>&1; then should_skip=true; fi
          if echo "$pr_title" | grep -Ei '^chore:' >/dev/null 2>&1; then should_skip=true; fi

          # Always build on beta-release branch to ensure artifacts for testing
          if [[ "$REF" == "refs/heads/feature/beta-release" ]]; then
            should_skip=false
            echo "Force building on beta-release branch"
          fi

          echo "skip_build=$should_skip" >> $GITHUB_OUTPUT

      - name: Set up QEMU
        if: steps.skip.outputs.skip_build != 'true'
        uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0

      - name: Set up Docker Buildx
        if: steps.skip.outputs.skip_build != 'true'
        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1

      - name: Resolve Caddy base digest
        if: steps.skip.outputs.skip_build != 'true'
        id: caddy
        run: |
          docker pull caddy:2-alpine
          DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' caddy:2-alpine)
          echo "image=$DIGEST" >> $GITHUB_OUTPUT

      - name: Log in to Container Registry
        if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata (tags, labels)
        if: steps.skip.outputs.skip_build != 'true'
        id: meta
        uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=raw,value=latest,enable={{is_default_branch}}
            type=raw,value=dev,enable=${{ github.ref == 'refs/heads/development' }}
            type=raw,value=beta,enable=${{ github.ref == 'refs/heads/feature/beta-release' }}
            type=raw,value=pr-${{ github.ref_name }},enable=${{ github.event_name == 'pull_request' }}
            type=sha,format=short,enable=${{ github.event_name != 'pull_request' }}

      - name: Build and push Docker image
        if: steps.skip.outputs.skip_build != 'true'
        id: build-and-push
        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
        with:
          context: .
          platforms: ${{ github.event_name == 'pull_request' && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
          build-args: |
            VERSION=${{ steps.meta.outputs.version }}
            BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
            VCS_REF=${{ github.sha }}
            CADDY_IMAGE=${{ steps.caddy.outputs.image }}

      - name: Run Trivy scan (table output)
        if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
        uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
        with:
          image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-and-push.outputs.digest }}
          format: 'table'
          severity: 'CRITICAL,HIGH'
          exit-code: '0'
        continue-on-error: true

      - name: Run Trivy vulnerability scanner (SARIF)
        if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
        id: trivy
        uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
        with:
          image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-and-push.outputs.digest }}
          format: 'sarif'
          output: 'trivy-results.sarif'
          severity: 'CRITICAL,HIGH'
        continue-on-error: true

      - name: Check Trivy SARIF exists
        if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
        id: trivy-check
        run: |
          if [ -f trivy-results.sarif ]; then
            echo "exists=true" >> $GITHUB_OUTPUT
          else
            echo "exists=false" >> $GITHUB_OUTPUT
          fi

      - name: Upload Trivy results
        if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' && steps.trivy-check.outputs.exists == 'true'
        uses: github/codeql-action/upload-sarif@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8
        with:
          sarif_file: 'trivy-results.sarif'
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Create summary
        if: steps.skip.outputs.skip_build != 'true'
        run: |
          echo "## 🎉 Docker Image Built Successfully!" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "### 📦 Image Details" >> $GITHUB_STEP_SUMMARY
          echo "- **Registry**: GitHub Container Registry (ghcr.io)" >> $GITHUB_STEP_SUMMARY
          echo "- **Repository**: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" >> $GITHUB_STEP_SUMMARY
          echo "- **Tags**: " >> $GITHUB_STEP_SUMMARY
          echo '```' >> $GITHUB_STEP_SUMMARY
          echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY
          echo '```' >> $GITHUB_STEP_SUMMARY

  test-image:
    name: Test Docker Image
    needs: build-and-push
    runs-on: ubuntu-latest
    if: needs.build-and-push.outputs.skip_build != 'true' && github.event_name != 'pull_request'

    steps:
      - name: Checkout repository
        uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6

      - name: Normalize image name
        run: |
          raw="${{ github.repository_owner }}/${{ github.event.repository.name }}"
          echo "IMAGE_NAME=$(echo "$raw" | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV

      - name: Determine image tag
        id: tag
        run: |
          if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
            echo "tag=latest" >> $GITHUB_OUTPUT
          elif [[ "${{ github.ref }}" == "refs/heads/development" ]]; then
            echo "tag=dev" >> $GITHUB_OUTPUT
          elif [[ "${{ github.ref }}" == refs/tags/v* ]]; then
            echo "tag=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
          else
            echo "tag=sha-$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT
          fi

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Pull Docker image
        run: docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}

      - name: Create Docker Network
        run: docker network create charon-test-net

      - name: Run Upstream Service (whoami)
        run: |
          docker run -d \
            --name whoami \
            --network charon-test-net \
            traefik/whoami

      - name: Run Charon Container
        run: |
          docker run -d \
            --name test-container \
            --network charon-test-net \
            -p 8080:8080 \
            -p 80:80 \
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}

      - name: Run Integration Test
        run: ./scripts/integration-test.sh

      - name: Check container logs
        if: always()
        run: docker logs test-container

      - name: Stop container
        if: always()
        run: |
          docker stop test-container whoami || true
          docker rm test-container whoami || true
          docker network rm charon-test-net || true

      - name: Create test summary
        if: always()
        run: |
          echo "## 🧪 Docker Image Test Results" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "- **Image**: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}" >> $GITHUB_STEP_SUMMARY
          echo "- **Integration Test**: ${{ job.status == 'success' && '✅ Passed' || '❌ Failed' }}" >> $GITHUB_STEP_SUMMARY

  trivy-pr-app-only:
    name: Trivy (PR) - App-only
    runs-on: ubuntu-latest
    if: github.event_name == 'pull_request'
    steps:
      - name: Checkout repository
        uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6

      - name: Build image locally for PR
        run: |
          docker build -t charon:pr-${{ github.sha }} .

      - name: Extract `charon` binary from image
        run: |
          CONTAINER=$(docker create charon:pr-${{ github.sha }})
          docker cp ${CONTAINER}:/app/charon ./charon_binary || true
          docker rm ${CONTAINER} || true

      - name: Run Trivy filesystem scan on `charon` (fail PR on HIGH/CRITICAL)
        run: |
          docker run --rm -v $HOME/.cache/trivy:/root/.cache/trivy -v $PWD:/workdir aquasec/trivy:latest fs --exit-code 1 --severity CRITICAL,HIGH /workdir/charon_binary
        shell: bash
