name: TakeoutSaaS CI/CD

on:
  pull_request:
    branches:
      - main
  workflow_dispatch:

env:
  REGISTRY: ${{ secrets.REGISTRY }}
  REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
  REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
  DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
  DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
  DEPLOY_PASSWORD: ${{ secrets.DEPLOY_PASSWORD }}
  REGISTRY_NAMESPACE: kjkj-saas

jobs:
  detect:
    runs-on: ubuntu-latest
    outputs:
      services: ${{ steps.collect.outputs.services }}
      image_tag: ${{ steps.collect.outputs.image_tag }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - id: collect
        shell: bash
        run: |
          set -euo pipefail

          BASE="${{ github.event.before }}"
          if [ -z "$BASE" ] || [ "$BASE" = "0000000000000000000000000000000000000000" ]; then
            if git rev-parse HEAD^ >/dev/null 2>&1; then
              BASE="$(git rev-parse HEAD^)"
            else
              BASE=""
            fi
          fi

          if [ -z "$BASE" ]; then
            CHANGED=$(git ls-tree -r --name-only HEAD)
          else
            CHANGED=$(git diff --name-only "$BASE" HEAD || true)
          fi

          echo "本次变更文件："
          echo "$CHANGED"

          deploy_all=false
          services=()

          hit() { echo "$CHANGED" | grep -qE "$1"; }

          if hit '^src/(Domain|Application|Infrastructure|Core|Modules)/'; then deploy_all=true; fi
          if hit '^Directory\.Build\.props$'; then deploy_all=true; fi

          if hit '^src/Api/TakeoutSaaS.AdminApi/'; then services+=("admin-api"); fi
          if hit '^src/Api/TakeoutSaaS.MiniApi/'; then services+=("mini-api"); fi
          if hit '^src/Api/TakeoutSaaS.UserApi/'; then services+=("user-api"); fi

          if $deploy_all || [ ${#services[@]} -eq 0 ]; then
            services=("admin-api" "mini-api" "user-api")
          fi

          printf '需要处理的服务: %s\n' "${services[*]}"

          SERVICES_LIST="${services[*]}"
          export SERVICES_LIST
          SERVICES_JSON=$(python -c "import json, os; print(json.dumps(os.environ.get('SERVICES_LIST','').split()))")

          echo "services=$SERVICES_JSON" >> "$GITHUB_OUTPUT"
          TAG=$(date +%Y%m%d%H%M%S)
          echo "image_tag=$TAG" >> "$GITHUB_OUTPUT"

  build:
    runs-on: ubuntu-latest
    needs: detect
    if: needs.detect.outputs.services != '[]'
    strategy:
      matrix:
        service: ${{ fromJson(needs.detect.outputs.services) }}
    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-buildx-action@v3

      - uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ env.REGISTRY_USERNAME }}
          password: ${{ env.REGISTRY_PASSWORD }}

      - name: Build and push ${{ matrix.service }}
        env:
          SERVICE: ${{ matrix.service }}
          IMAGE_TAG: ${{ needs.detect.outputs.image_tag }}
        run: |
          set -euo pipefail

          case "$SERVICE" in
            admin-api)
              DOCKERFILE="src/Api/TakeoutSaaS.AdminApi/Dockerfile"
              IMAGE="$REGISTRY/$REGISTRY_NAMESPACE/admin-api:$IMAGE_TAG"
              ;;
            mini-api)
              DOCKERFILE="src/Api/TakeoutSaaS.MiniApi/Dockerfile"
              IMAGE="$REGISTRY/$REGISTRY_NAMESPACE/mini-api:$IMAGE_TAG"
              ;;
            user-api)
              DOCKERFILE="src/Api/TakeoutSaaS.UserApi/Dockerfile"
              IMAGE="$REGISTRY/$REGISTRY_NAMESPACE/user-api:$IMAGE_TAG"
              ;;
            *)
              echo "未知服务：$SERVICE"
              exit 1
              ;;
          esac

          if [ ! -f "$DOCKERFILE" ]; then
            echo "未找到 Dockerfile: $DOCKERFILE"
            exit 1
          fi

          docker build -f "$DOCKERFILE" -t "$IMAGE" .
          docker push "$IMAGE"

  deploy:
    runs-on: ubuntu-latest
    needs:
      - detect
      - build
    if: needs.detect.outputs.services != '[]'
    strategy:
      matrix:
        service: ${{ fromJson(needs.detect.outputs.services) }}
    steps:
      - name: Install sshpass
        run: sudo apt-get update && sudo apt-get install -y sshpass

      - name: Deploy ${{ matrix.service }}
        env:
          SERVICE: ${{ matrix.service }}
          IMAGE_TAG: ${{ needs.detect.outputs.image_tag }}
        run: |
          set -euo pipefail

          case "$SERVICE" in
            admin-api)
              IMAGE="$REGISTRY/$REGISTRY_NAMESPACE/admin-api:$IMAGE_TAG"
              PORT=7801
              ;;
            mini-api)
              IMAGE="$REGISTRY/$REGISTRY_NAMESPACE/mini-api:$IMAGE_TAG"
              PORT=7701
              ;;
            user-api)
              IMAGE="$REGISTRY/$REGISTRY_NAMESPACE/user-api:$IMAGE_TAG"
              PORT=7901
              ;;
            *)
              echo "未知服务：$SERVICE"
              exit 1
              ;;
          esac

          sshpass -p "$DEPLOY_PASSWORD" ssh -o StrictHostKeyChecking=no "$DEPLOY_USER@$DEPLOY_HOST" "
          set -e
          echo \"$REGISTRY_PASSWORD\" | docker login \"$REGISTRY\" -u \"$REGISTRY_USERNAME\" --password-stdin
          docker pull $IMAGE
          docker stop $SERVICE 2>/dev/null || true
          docker rm $SERVICE 2>/dev/null || true
          docker run -d --name $SERVICE --restart=always -p $PORT:$PORT $IMAGE
          # 清理同一服务旧镜像，避免磁盘被历史 tag 占满
          docker images \"$REGISTRY/$REGISTRY_NAMESPACE/$SERVICE\" --format '{{.Repository}}:{{.Tag}}' \
            | grep -v -x \"$IMAGE\" \
            | xargs -r docker rmi -f
          "
