name: CD – Build, Push & Deploy

on:
  push:
    branches: [main]
  workflow_dispatch:

concurrency:
  group: deploy-production
  cancel-in-progress: false

env:
  REGISTRY: ghcr.io
  API_IMAGE: ghcr.io/taaazzz-prog/rollerlogic-api
  ADMIN_IMAGE: ghcr.io/taaazzz-prog/rollerlogic-admin
  MAINTENANCE_IMAGE: ghcr.io/taaazzz-prog/rollerlogic-maintenance
  REMOTE_PATH: /home/taaazzz/RollerLogic

jobs:
  # ─── Étape 1 : CI (lint, typecheck, tests) ───
  ci:
    if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')"
    runs-on: self-hosted
    strategy:
      fail-fast: true
      matrix:
        project: [rollerlogic-api, rollerlogic-mobile]
    steps:
      - uses: actions/checkout@v4

      - name: Détecter les fichiers modifiés
        uses: dorny/paths-filter@v3
        id: code-changes
        with:
          filters: |
            api-code:
              - 'rollerlogic-api/src/**'
              - 'rollerlogic-api/package.json'
            mobile-code:
              - 'rollerlogic-mobile/src/**'
              - 'rollerlogic-mobile/package.json'
            docs-only:
              - '**.md'
              - '**.txt'
              - 'docs/**'

      - uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: "npm"
          cache-dependency-path: |
            rollerlogic-api/package-lock.json
            rollerlogic-mobile/package-lock.json

      - name: Install
        working-directory: ${{ matrix.project }}
        run: npm ci --prefer-offline

      - name: Typecheck / Build
        working-directory: ${{ matrix.project }}
        run: npm run build

      - name: Tests
        if: |
          (matrix.project == 'rollerlogic-api' && steps.code-changes.outputs.api-code == 'true') ||
          (matrix.project == 'rollerlogic-mobile' && steps.code-changes.outputs.mobile-code == 'true')
        working-directory: ${{ matrix.project }}
        run: npm test

  # ─── Étape 2 : Build & Push des images Docker ───
  build-and-push:
    needs: ci
    if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')"
    runs-on: self-hosted
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4

      - name: Détecter les fichiers modifiés
        uses: dorny/paths-filter@v3
        id: changes
        with:
          filters: |
            api:
              - 'rollerlogic-api/**'
              - 'rollerlogic-mobile/**'
              - 'Dockerfile'
              - 'package.json'
              - 'package-lock.json'
            admin:
              - 'admin/**'
            admin-impact:
              - 'rollerlogic-api/src/routes/admin-*.ts'
              - 'rollerlogic-api/src/routes/auth-routes.ts'
              - 'rollerlogic-api/src/server/admin-service.ts'
              - 'rollerlogic-api/src/server/data-fetchers.ts'
              - 'rollerlogic-api/src/server/user-service.ts'
              - 'rollerlogic-api/src/server/types.ts'
              - 'rollerlogic-api/src/server.ts'
              - 'rollerlogic-api/src/config.ts'
            maintenance:
              - 'maintenance/**'

      - name: Vérifier force rebuild
        id: force-rebuild
        run: |
          MSG="${{ github.event.head_commit.message }}"
          if [[ "$MSG" == *"[rebuild-all]"* ]]; then
            echo "force=true" >> "$GITHUB_OUTPUT"
            echo "force-admin=true" >> "$GITHUB_OUTPUT"
            echo "force-maintenance=true" >> "$GITHUB_OUTPUT"
            echo "🔄 Force rebuild global activé ([rebuild-all])"
          else
            echo "force=false" >> "$GITHUB_OUTPUT"
            if [[ "$MSG" == *"[rebuild-admin]"* ]]; then
              echo "force-admin=true" >> "$GITHUB_OUTPUT"
            else
              echo "force-admin=false" >> "$GITHUB_OUTPUT"
            fi
            if [[ "$MSG" == *"[rebuild-maintenance]"* ]]; then
              echo "force-maintenance=true" >> "$GITHUB_OUTPUT"
            else
              echo "force-maintenance=false" >> "$GITHUB_OUTPUT"
            fi
          fi

      - name: Extraire la version API depuis package.json
        id: api-version
        run: |
          VERSION=$(node -p "require('./rollerlogic-api/package.json').version")
          echo "version=v${VERSION}" >> "$GITHUB_OUTPUT"
          echo "📦 Version: v${VERSION}"

      - name: Extraire le short SHA
        id: sha
        run: |
          SHORT_SHA=$(echo $GITHUB_SHA | cut -c1-7)
          echo "short=${SHORT_SHA}" >> "$GITHUB_OUTPUT"
          echo "🏷️ Tag: ${SHORT_SHA}"

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build & Push API image
        if: steps.changes.outputs.api == 'true' || steps.force-rebuild.outputs.force == 'true'
        run: |
          docker build \
            --build-arg VITE_API_URL=/api \
            --build-arg VITE_STRIPE_ENABLED=true \
            -t ${{ env.API_IMAGE }}:${{ steps.api-version.outputs.version }} \
            -t ${{ env.API_IMAGE }}:${{ steps.sha.outputs.short }} \
            -t ${{ env.API_IMAGE }}:latest \
            -f ./Dockerfile .
          docker push ${{ env.API_IMAGE }}:${{ steps.api-version.outputs.version }}
          docker push ${{ env.API_IMAGE }}:${{ steps.sha.outputs.short }}
          docker push ${{ env.API_IMAGE }}:latest

      - name: Build & Push Admin image
        if: steps.changes.outputs.admin == 'true' || steps.changes.outputs.admin-impact == 'true' || steps.force-rebuild.outputs.force == 'true' || steps.force-rebuild.outputs.force-admin == 'true'
        run: |
          docker build \
            -t ${{ env.ADMIN_IMAGE }}:${{ steps.api-version.outputs.version }} \
            -t ${{ env.ADMIN_IMAGE }}:${{ steps.sha.outputs.short }} \
            -t ${{ env.ADMIN_IMAGE }}:latest \
            -f ./admin/Dockerfile.production ./admin
          docker push ${{ env.ADMIN_IMAGE }}:${{ steps.api-version.outputs.version }}
          docker push ${{ env.ADMIN_IMAGE }}:${{ steps.sha.outputs.short }}
          docker push ${{ env.ADMIN_IMAGE }}:latest

      - name: Build & Push Maintenance image
        if: steps.changes.outputs.maintenance == 'true' || steps.force-rebuild.outputs.force == 'true' || steps.force-rebuild.outputs.force-maintenance == 'true'
        run: |
          docker build \
            -t ${{ env.MAINTENANCE_IMAGE }}:${{ steps.api-version.outputs.version }} \
            -t ${{ env.MAINTENANCE_IMAGE }}:${{ steps.sha.outputs.short }} \
            -t ${{ env.MAINTENANCE_IMAGE }}:latest \
            -f ./maintenance/Dockerfile ./maintenance
          docker push ${{ env.MAINTENANCE_IMAGE }}:${{ steps.api-version.outputs.version }}
          docker push ${{ env.MAINTENANCE_IMAGE }}:${{ steps.sha.outputs.short }}
          docker push ${{ env.MAINTENANCE_IMAGE }}:latest

      - name: 🧹 Nettoyage images obsolètes
        run: docker image prune -f

    outputs:
      deploy-tag: ${{ steps.sha.outputs.short }}
      version: ${{ steps.api-version.outputs.version }}
      api-changed: ${{ steps.changes.outputs.api }}
      admin-changed: ${{ steps.changes.outputs.admin }}
      admin-impact-changed: ${{ steps.changes.outputs.admin-impact }}
      maintenance-changed: ${{ steps.changes.outputs.maintenance }}
      force-rebuild: ${{ steps.force-rebuild.outputs.force }}
      force-admin-rebuild: ${{ steps.force-rebuild.outputs.force-admin }}
      force-maintenance-rebuild: ${{ steps.force-rebuild.outputs.force-maintenance }}

  # ─── Étape 3 : Déploiement sur OVH ───
  deploy:
    needs: build-and-push
    runs-on: self-hosted
    environment: production
    steps:
      - uses: actions/checkout@v4

      - name: Afficher les services modifiés
        run: |
          echo "📦 Services à déployer:"
          if [[ "${{ needs.build-and-push.outputs.api-changed }}" == "true" ]] || [[ "${{ needs.build-and-push.outputs.force-rebuild }}" == "true" ]]; then
            echo "  ✅ API"
          else
            echo "  ⏭️  API (aucun changement)"
          fi
          if [[ "${{ needs.build-and-push.outputs.admin-changed }}" == "true" ]] || [[ "${{ needs.build-and-push.outputs.admin-impact-changed }}" == "true" ]] || [[ "${{ needs.build-and-push.outputs.force-rebuild }}" == "true" ]] || [[ "${{ needs.build-and-push.outputs.force-admin-rebuild }}" == "true" ]]; then
            echo "  ✅ Admin Panel"
          else
            echo "  ⏭️  Admin Panel (aucun changement)"
          fi
          if [[ "${{ needs.build-and-push.outputs.maintenance-changed }}" == "true" ]] || [[ "${{ needs.build-and-push.outputs.force-rebuild }}" == "true" ]] || [[ "${{ needs.build-and-push.outputs.force-maintenance-rebuild }}" == "true" ]]; then
            echo "  ✅ Maintenance"
          else
            echo "  ⏭️  Maintenance (aucun changement)"
          fi

      - name: Mettre à jour les tags images dans le stack file
        run: |
          TAG="${{ needs.build-and-push.outputs.deploy-tag }}"
          VERSION="${{ needs.build-and-push.outputs.version }}"
          echo "🚀 Déploiement avec le tag: ${TAG} (${VERSION})"

          if [[ "${{ needs.build-and-push.outputs.api-changed }}" == "true" ]] || [[ "${{ needs.build-and-push.outputs.force-rebuild }}" == "true" ]]; then
            sed -i "s|ghcr.io/taaazzz-prog/rollerlogic-api:[^ ]*|ghcr.io/taaazzz-prog/rollerlogic-api:${TAG}|g" rollerlogic-stack.yml
          fi
          if [[ "${{ needs.build-and-push.outputs.admin-changed }}" == "true" ]] || [[ "${{ needs.build-and-push.outputs.admin-impact-changed }}" == "true" ]] || [[ "${{ needs.build-and-push.outputs.force-rebuild }}" == "true" ]] || [[ "${{ needs.build-and-push.outputs.force-admin-rebuild }}" == "true" ]]; then
            sed -i "s|ghcr.io/taaazzz-prog/rollerlogic-admin:[^ ]*|ghcr.io/taaazzz-prog/rollerlogic-admin:${TAG}|g" rollerlogic-stack.yml
          fi
          if [[ "${{ needs.build-and-push.outputs.maintenance-changed }}" == "true" ]] || [[ "${{ needs.build-and-push.outputs.force-rebuild }}" == "true" ]] || [[ "${{ needs.build-and-push.outputs.force-maintenance-rebuild }}" == "true" ]]; then
            sed -i "s|ghcr.io/taaazzz-prog/rollerlogic-maintenance:[^ ]*|ghcr.io/taaazzz-prog/rollerlogic-maintenance:${TAG}|g" rollerlogic-stack.yml
          fi

          echo "--- Stack file final ---"
          grep "image:" rollerlogic-stack.yml

      - name: Copier le stack file
        run: cp rollerlogic-stack.yml ${{ env.REMOTE_PATH }}/rollerlogic-stack.yml

      - name: Déployer le stack Docker Swarm
        run: |
          set -euo pipefail

          echo "🔐 Login GHCR..."
          echo "${{ secrets.GHCR_PAT }}" | docker login ghcr.io -u taaazzz-prog --password-stdin

          echo "🚀 Déploiement du stack..."
          cd ${{ env.REMOTE_PATH }}
          docker stack deploy -c rollerlogic-stack.yml rollerlogic --with-registry-auth

          echo "⏳ Attente du démarrage..."
          sleep 15

          echo "📊 État des services:"
          docker service ls | grep rollerlogic

          echo "🏥 Healthcheck:"
          curl -sf https://rollerlogic.com/api/health && echo " ✅ API OK" || echo " ⚠️ API pas encore prête"

          echo "🔖 Version déployée:"
          curl -sf https://api.rollerlogic.com/version || true
