name: Build, Tag, Push, and Release to GitHub Container Registry

on:
  push:
    branches:
      - 'master'
      - 'develop'
  pull_request:
    branches:
      - '**'

jobs:
  check-for-migrations:
    name: Check for DB Migrations
    if: github.event_name == 'pull_request' && ((github.base_ref == 'master' && github.head_ref == 'develop') || github.base_ref == 'develop')
    runs-on: ubuntu-latest
    outputs:
      has_migrations: ${{ steps.check_migrations.outputs.has_migrations }}
    steps:
      - name: Checkout Repository for Diff
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Detect Flyway Migration Changes
        id: check_migrations
        run: |
          # Compare PR head with the target base branch
          if git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -q "booklore-api/src/main/resources/db/migration/V.*.sql"; then
            echo "Migration file changes detected. Proceeding with migration preview."
            echo "has_migrations=true" >> $GITHUB_OUTPUT
          else
            echo "No migration file changes detected. Skipping migration preview."
            echo "has_migrations=false" >> $GITHUB_OUTPUT
          fi

  flyway-migration-preview:
    name: Flyway DB Migration Preview
    needs: [check-for-migrations]
    if: needs.check-for-migrations.outputs.has_migrations == 'true'
    runs-on: ubuntu-latest
    services:
      mariadb:
        image: mariadb:10.6
        env:
          MYSQL_ROOT_PASSWORD: root
          MYSQL_DATABASE: booklore_test
        ports:
          - 3306:3306
        options: >-
          --health-cmd="mysqladmin ping --silent"
          --health-interval=5s
          --health-timeout=5s
          --health-retries=10

    steps:
      - name: Checkout Base Branch
        uses: actions/checkout@v6
        with:
          ref: '${{ github.base_ref }}'

      - name: Apply Migrations from Base Branch
        run: |
          echo "Applying migrations from '${{ github.base_ref }}' branch..."
          docker run --network host \
            -v ${{ github.workspace }}:/flyway/sql \
            flyway/flyway:11.19.0-alpine \
            -url=jdbc:mariadb://127.0.0.1:3306/booklore_test \
            -user=root -password=root \
            -locations=filesystem:/flyway/sql/booklore-api/src/main/resources/db/migration \
            migrate

      - name: Checkout Pull Request Branch
        uses: actions/checkout@v6

      - name: Apply Migrations from PR Branch
        run: |
          echo "Applying new migrations from PR branch..."
          docker run --network host \
            -v ${{ github.workspace }}:/flyway/sql \
            flyway/flyway:11.19.0-alpine \
            -url=jdbc:mariadb://127.0.0.1:3306/booklore_test \
            -user=root -password=root \
            -locations=filesystem:/flyway/sql/booklore-api/src/main/resources/db/migration \
            migrate
      
      - name: Confirm Flyway Dry Run Success
        run: echo "✅ Flyway migration preview successful. Migrations can be applied cleanly."

  build-and-push:
    needs: [check-for-migrations, flyway-migration-preview]
    if: always() && (needs.flyway-migration-preview.result == 'success' || needs.flyway-migration-preview.result == 'skipped')
    runs-on: ubuntu-latest

    permissions:
      contents: write
      packages: write
      issues: read
      checks: write
      pull-requests: write

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Authenticate to Docker Hub
        if: github.event_name == 'push'
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Authenticate to GitHub Container Registry
        if: github.event_name == 'push'
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ github.token }}

      - name: Set Up QEMU for Multi-Architecture Builds
        uses: docker/setup-qemu-action@v3

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

      - name: Set Up JDK 21
        uses: actions/setup-java@v5
        with:
          java-version: '21'
          distribution: 'temurin'
          cache: 'gradle'

      - name: Execute Backend Tests
        id: backend_tests
        working-directory: ./booklore-api
        run: |
          echo "Running backend tests with testcontainers..."
          ./gradlew test --no-daemon --parallel --build-cache
        continue-on-error: true

      - name: Publish Backend Test Results
        uses: EnricoMi/publish-unit-test-result-action@v2
        if: always()
        with:
          files: booklore-api/build/test-results/**/*.xml
          check_name: Backend Test Results
          comment_title: Backend Test Results
          report_individual_runs: true
          report_suite_logs: 'any'

      - name: Upload Backend Test Reports
        uses: actions/upload-artifact@v6
        if: always()
        with:
          name: test-reports
          path: |
            booklore-api/build/reports/tests/
            booklore-api/build/test-results/
          retention-days: 30

      - name: Validate Backend Test Results
        if: steps.backend_tests.outcome == 'failure'
        run: |
          echo "❌ Backend tests failed! Check the test results above."
          exit 1

      - name: Retrieve Latest Master Version Tag
        id: get_version
        run: |
          latest_tag=$(git tag --list "v*" --sort=-v:refname | head -n 1)
          latest_tag=${latest_tag:-"v0.0.0"}
          echo "latest_tag=$latest_tag" >> $GITHUB_ENV
          echo "Latest master tag: $latest_tag"

      - name: Determine Version Bump (Master Only)
        if: github.ref == 'refs/heads/master'
        id: determine_bump
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          echo "Determining version bump from PR labels..."

          # Extract PR number from merge commit
          pr_number=$(git log -1 --pretty=%B | grep -oE 'Merge pull request #[0-9]+' | grep -oE '[0-9]+') || true
          if [ -z "$pr_number" ]; then
            pr_number=$(gh pr list --state merged --base master --limit 1 --json number --jq '.[0].number')
          fi
          echo "PR number: $pr_number"

          labels=$(gh pr view "$pr_number" --json labels --jq '.labels[].name' || echo "")
          echo "PR labels: $labels"

          if echo "$labels" | grep -q 'bump:major'; then
            bump="major"
          elif echo "$labels" | grep -q 'bump:minor'; then
            bump="minor"
          elif echo "$labels" | grep -q 'bump:patch'; then
            bump="patch"
          else
            last_commit_msg=$(git log -1 --pretty=%B)
            if echo "$last_commit_msg" | grep -iq '#major'; then
              bump="major"
            elif echo "$last_commit_msg" | grep -iq '#minor'; then
              bump="minor"
            elif echo "$last_commit_msg" | grep -iq '#patch'; then
              bump="patch"
            else
              bump="patch"
            fi
          fi

          # Calculate next version
          semver=$(echo ${{ env.latest_tag }} | sed 's/^v//')
          major=$(echo $semver | cut -d. -f1)
          minor=$(echo $semver | cut -d. -f2)
          patch=$(echo $semver | cut -d. -f3)

          case "$bump" in
            major) major=$((major+1)); minor=0; patch=0 ;;
            minor) minor=$((minor+1)); patch=0 ;;
            patch) patch=$((patch+1)) ;;
          esac

          next_version="v${major}.${minor}.${patch}"
          echo "Version bump type: $bump"
          echo "Next version: $next_version"

          echo "bump=$bump" >> $GITHUB_ENV
          echo "new_tag=$next_version" >> $GITHUB_ENV

      - name: Generate Image Tag
        id: set_image_tag
        run: |
          branch="${GITHUB_REF#refs/heads/}"
          if [[ "$branch" == "master" ]]; then
            image_tag="${{ env.new_tag }}"
          elif [[ "$branch" == "develop" ]]; then
            short_sha=$(git rev-parse --short HEAD)
            image_tag="${{ env.latest_tag }}-develop-${short_sha}"
          else
            short_sha=$(git rev-parse --short HEAD)
            image_tag="${short_sha}"
          fi
          echo "image_tag=$image_tag" >> $GITHUB_ENV
          echo "Image tag: $image_tag"

      - name: Build and push Docker image
        if: github.event_name == 'push'
        uses: docker/build-push-action@v6
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: |
            booklore/booklore:${{ env.image_tag }}
            ghcr.io/booklore-app/booklore:${{ env.image_tag }}
          build-args: |
            APP_VERSION=${{ env.image_tag }}
            APP_REVISION=${{ github.sha }}
          cache-from: |
            type=gha
            type=registry,ref=ghcr.io/booklore-app/booklore:buildcache
          cache-to: |
            type=gha,mode=max
            type=registry,ref=ghcr.io/booklore-app/booklore:buildcache,mode=max

      - name: Push Latest Tag (Master Only)
        if: github.ref == 'refs/heads/master' && github.event_name == 'push'
        uses: docker/build-push-action@v6
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: |
            booklore/booklore:latest
            booklore/booklore:${{ env.new_tag }}
            ghcr.io/booklore-app/booklore:latest
            ghcr.io/booklore-app/booklore:${{ env.new_tag }}
          build-args: |
            APP_VERSION=${{ env.new_tag }}
            APP_REVISION=${{ github.sha }}
          cache-from: type=gha

      - name: Update GitHub Release Draft (Master Only)
        if: github.ref == 'refs/heads/master'
        uses: release-drafter/release-drafter@v6
        with:
          tag: ${{ env.new_tag }}
          name: "Release ${{ env.new_tag }}"
        env:
          GITHUB_TOKEN: ${{ github.token }}

      - name: Publish GitHub Draft Release (Master Only)
        if: github.ref == 'refs/heads/master'
        env:
          GITHUB_TOKEN: ${{ github.token }}
        run: |
          gh release edit ${{ env.new_tag }} --draft=true
