name: Backend Services CI/CD

on:
  push:
    branches: [ main, develop ]
    paths:
      - 'user/**'
      - 'meeting/**'
      - 'stt/**'
      - 'ai/**'
      - 'notification/**'
      - 'common/**'
      - '.github/**'
  pull_request:
    branches: [ main ]
  workflow_dispatch:
    inputs:
      ENVIRONMENT:
        description: 'Target environment'
        required: true
        default: 'dev'
        type: choice
        options:
          - dev
          - staging
          - prod
      SKIP_SONARQUBE:
        description: 'Skip SonarQube Analysis'
        required: false
        default: 'true'
        type: choice
        options:
          - 'true'
          - 'false'

env:
  REGISTRY: acrdigitalgarage02.azurecr.io
  IMAGE_ORG: hgzero
  RESOURCE_GROUP: rg-digitalgarage-02
  AKS_CLUSTER: aks-digitalgarage-02
  NAMESPACE: hgzero

jobs:
  build:
    name: Build and Test
    runs-on: ubuntu-latest
    outputs:
      image_tag: ${{ steps.set_outputs.outputs.image_tag }}
      environment: ${{ steps.set_outputs.outputs.environment }}

    steps:
      - name: Check out code
        uses: actions/checkout@v4

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

      - name: Determine environment
        id: determine_env
        run: |
          # Use input parameter or default to 'dev'
          ENVIRONMENT="${{ github.event.inputs.ENVIRONMENT || 'dev' }}"
          echo "environment=$ENVIRONMENT" >> $GITHUB_OUTPUT

      - name: Load environment variables
        id: env_vars
        run: |
          ENV=${{ steps.determine_env.outputs.environment }}

          # Initialize variables with defaults
          REGISTRY="acrdigitalgarage02.azurecr.io"
          IMAGE_ORG="hgzero"
          RESOURCE_GROUP="rg-digitalgarage-02"
          AKS_CLUSTER="aks-digitalgarage-02"
          NAMESPACE="hgzero"

          # Read environment variables from .github/config file
          if [[ -f ".github/config/deploy_env_vars_${ENV}" ]]; then
            while IFS= read -r line || [[ -n "$line" ]]; do
              # Skip comments and empty lines
              [[ "$line" =~ ^#.*$ ]] && continue
              [[ -z "$line" ]] && continue

              # Extract key-value pairs
              key=$(echo "$line" | cut -d '=' -f1)
              value=$(echo "$line" | cut -d '=' -f2-)

              # Override defaults if found in config
              case "$key" in
                "resource_group") RESOURCE_GROUP="$value" ;;
                "cluster_name") AKS_CLUSTER="$value" ;;
              esac
            done < ".github/config/deploy_env_vars_${ENV}"
          fi

          # Export for other jobs
          echo "REGISTRY=$REGISTRY" >> $GITHUB_ENV
          echo "IMAGE_ORG=$IMAGE_ORG" >> $GITHUB_ENV
          echo "RESOURCE_GROUP=$RESOURCE_GROUP" >> $GITHUB_ENV
          echo "AKS_CLUSTER=$AKS_CLUSTER" >> $GITHUB_ENV

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

      - name: Build with Gradle
        run: |
          ./gradlew build -x test

      - name: SonarQube Analysis & Quality Gate
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
        run: |
          # Check if SonarQube should be skipped
          SKIP_SONARQUBE="${{ github.event.inputs.SKIP_SONARQUBE || 'true' }}"

          if [[ "$SKIP_SONARQUBE" == "true" ]]; then
            echo "⏭️ Skipping SonarQube Analysis (SKIP_SONARQUBE=$SKIP_SONARQUBE)"
            exit 0
          fi

          # Define services array
          services=(user meeting stt ai notification)

          # Run tests, coverage reports, and SonarQube analysis for each service
          for service in "${services[@]}"; do
            ./gradlew :$service:test :$service:jacocoTestReport :$service:sonar \
              -Dsonar.projectKey=hgzero-$service-${{ steps.determine_env.outputs.environment }} \
              -Dsonar.projectName=hgzero-$service-${{ steps.determine_env.outputs.environment }} \
              -Dsonar.host.url=$SONAR_HOST_URL \
              -Dsonar.token=$SONAR_TOKEN \
              -Dsonar.java.binaries=build/classes/java/main \
              -Dsonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml \
              -Dsonar.exclusions=**/config/**,**/entity/**,**/dto/**,**/*Application.class,**/exception/**
          done

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: app-builds
          path: |
            user/build/libs/*.jar
            meeting/build/libs/*.jar
            stt/build/libs/*.jar
            ai/build/libs/*.jar
            notification/build/libs/*.jar

      - name: Set outputs
        id: set_outputs
        run: |
          # Generate timestamp for image tag
          IMAGE_TAG=$(date +%Y%m%d%H%M%S)
          echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT
          echo "environment=${{ steps.determine_env.outputs.environment }}" >> $GITHUB_OUTPUT

  release:
    name: Build and Push Docker Images
    needs: build
    runs-on: ubuntu-latest

    steps:
      - name: Check out code
        uses: actions/checkout@v4

      - name: Download build artifacts
        uses: actions/download-artifact@v4
        with:
          name: app-builds

      - name: Set environment variables from build job
        run: |
          echo "REGISTRY=${{ env.REGISTRY }}" >> $GITHUB_ENV
          echo "IMAGE_ORG=${{ env.IMAGE_ORG }}" >> $GITHUB_ENV
          echo "ENVIRONMENT=${{ needs.build.outputs.environment }}" >> $GITHUB_ENV
          echo "IMAGE_TAG=${{ needs.build.outputs.image_tag }}" >> $GITHUB_ENV

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

      - name: Login to Docker Hub (prevent rate limit)
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_PASSWORD }}

      - name: Login to Azure Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ secrets.ACR_USERNAME }}
          password: ${{ secrets.ACR_PASSWORD }}

      - name: Build and push Docker images for all services
        run: |
          # Define services array
          services=(user meeting stt ai notification)

          # Build and push each service image
          for service in "${services[@]}"; do
            echo "Building and pushing $service..."
            docker build \
              --build-arg BUILD_LIB_DIR="$service/build/libs" \
              --build-arg ARTIFACTORY_FILE="$service.jar" \
              -f deployment/container/Dockerfile-backend \
              -t ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/$service:${{ needs.build.outputs.environment }}-${{ needs.build.outputs.image_tag }} .

            docker push ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/$service:${{ needs.build.outputs.environment }}-${{ needs.build.outputs.image_tag }}
          done

  deploy:
    name: Deploy to Kubernetes
    needs: [build, release]
    runs-on: ubuntu-latest

    steps:
      - name: Check out code
        uses: actions/checkout@v4

      - name: Set image tag environment variable
        run: |
          echo "IMAGE_TAG=${{ needs.build.outputs.image_tag }}" >> $GITHUB_ENV
          echo "ENVIRONMENT=${{ needs.build.outputs.environment }}" >> $GITHUB_ENV

      - name: Install Azure CLI
        run: |
          curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

      - name: Azure Login
        uses: azure/login@v1
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}

      - name: Setup kubectl
        uses: azure/setup-kubectl@v3

      - name: Get AKS Credentials
        run: |
          az aks get-credentials --resource-group ${{ env.RESOURCE_GROUP }} --name ${{ env.AKS_CLUSTER }} --overwrite-existing

      - name: Create namespace
        run: |
          kubectl create namespace ${{ env.NAMESPACE }} --dry-run=client -o yaml | kubectl apply -f -

      - name: Install Kustomize
        run: |
          curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
          sudo mv kustomize /usr/local/bin/

      - name: Update Kustomize images and deploy
        run: |
          # 환경별 디렉토리로 이동
          cd .github/kustomize/overlays/${{ env.ENVIRONMENT }}

          # 각 서비스별 이미지 태그 업데이트
          kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/user:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
          kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/meeting:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
          kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/stt:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
          kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/ai:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
          kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/notification:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}

          # 매니페스트 적용
          kubectl apply -k .

      - name: Wait for deployments to be ready
        run: |
          echo "Waiting for deployments to be ready..."
          kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/user --timeout=300s || true
          kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/meeting --timeout=300s || true
          kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/stt --timeout=300s || true
          kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/ai --timeout=300s || true
          kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/notification --timeout=300s || true
