name: Build & Deploy

on:
  push:
    branches:
      - main
    tags:
      - 'v*'
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}
  cancel-in-progress: false

jobs:
  prepare:
    name: 🔍 Prepare Environment
    runs-on: docker
    container:
      image: catthehacker/ubuntu:act-latest
    outputs:
      target:           ${{ steps.determine.outputs.target }}
      image_tag:        ${{ steps.determine.outputs.image_tag }}
      env_file:         ${{ steps.determine.outputs.env_file }}
      traefik_host:     ${{ steps.determine.outputs.traefik_host }}
      next_public_base_url: ${{ steps.determine.outputs.next_public_base_url }}
      directus_url:     ${{ steps.determine.outputs.directus_url }}
      directus_host:    ${{ steps.determine.outputs.directus_host }}
      project_name:     ${{ steps.determine.outputs.project_name }}
    steps:
      - name: 🔍 Debug Info
        shell: bash
        run: |
          echo "ref_name: ${{ github.ref_name }}"
          echo "ref_type: ${{ github.ref_type }}"
          echo "tag: ${{ github.ref_name }}"

      - name: 🧹 Maintenance (Runner Cleanup)
        continue-on-error: true
        shell: bash
        run: |
          docker image prune -f || true
          docker builder prune -f --filter "until=24h" || true

      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 2

      - name: 🔍 Determine Environment
        id: determine
        shell: bash
        run: |
          TAG="${{ github.ref_name }}"
          SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
          DOMAIN_BASE="mb-grid-solutions.com"
          PRJ_ID="mb-grid-solutions"

          if [[ "${{ github.ref_type }}" == "branch" && "$TAG" == "main" ]]; then
            TARGET="staging"
            IMAGE_TAG="staging-${SHORT_SHA}"
            ENV_FILE=".env.staging"
            TRAEFIK_HOST="\`staging.${DOMAIN_BASE}\`"
            NEXT_PUBLIC_BASE_URL="https://staging.${DOMAIN_BASE}"
            DIRECTUS_URL="https://cms.staging.${DOMAIN_BASE}"
            DIRECTUS_HOST="\`cms.staging.${DOMAIN_BASE}\`"
          elif [[ "${{ github.ref_type }}" == "tag" ]]; then
            TARGET="production"
            IMAGE_TAG="$TAG"
            ENV_FILE=".env.prod"
            TRAEFIK_HOST="\`${DOMAIN_BASE}\`, \`www.${DOMAIN_BASE}\`"
            NEXT_PUBLIC_BASE_URL="https://${DOMAIN_BASE}"
            DIRECTUS_URL="https://cms.${DOMAIN_BASE}"
            DIRECTUS_HOST="\`cms.${DOMAIN_BASE}\`"
          else
            TARGET="skip"
          fi

          echo "Target determined: $TARGET"
          echo "target=$TARGET" >> "$GITHUB_OUTPUT"
          echo "image_tag=$IMAGE_TAG" >> "$GITHUB_OUTPUT"
          echo "env_file=$ENV_FILE" >> "$GITHUB_OUTPUT"
          echo "traefik_host=$TRAEFIK_HOST" >> "$GITHUB_OUTPUT"
          echo "next_public_base_url=$NEXT_PUBLIC_BASE_URL" >> "$GITHUB_OUTPUT"
          echo "directus_url=$DIRECTUS_URL" >> "$GITHUB_OUTPUT"
          echo "directus_host=$DIRECTUS_HOST" >> "$GITHUB_OUTPUT"
          echo "project_name=$PRJ_ID-$TARGET" >> "$GITHUB_OUTPUT"

  qa:
    name: 🧪 QA
    needs: prepare
    if: needs.prepare.outputs.target != 'skip'
    runs-on: docker
    container:
      image: catthehacker/ubuntu:act-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile
        env:
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
      - run: pnpm lint
      - run: pnpm build
        env:
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
          NEXT_PUBLIC_BASE_URL: https://dummy.test

  build:
    name: 🏗️ Build
    needs: prepare
    if: needs.prepare.outputs.target != 'skip'
    runs-on: docker
    container:
      image: catthehacker/ubuntu:act-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

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

      - name: 🔐 Registry Login
        run: echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
      
      - name: 🏗️ Build and Push
        shell: bash
        run: |
          docker buildx build \
            --pull \
            --platform linux/amd64,linux/arm64 \
            --build-arg NPM_TOKEN=${{ secrets.NPM_TOKEN }} \
            --build-arg NEXT_PUBLIC_BASE_URL=${{ needs.prepare.outputs.next_public_base_url }} \
            --build-arg DIRECTUS_URL=${{ needs.prepare.outputs.directus_url }} \
            -t registry.infra.mintel.me/mintel/mb-grid-solutions:${{ needs.prepare.outputs.image_tag }} \
            --push .

  deploy:
    name: 🚀 Deploy
    needs: [prepare, build, qa]
    if: needs.prepare.outputs.target != 'skip'
    runs-on: docker
    container:
      image: catthehacker/ubuntu:act-latest
    steps:
      - name: 🚀 Deploy via SSH
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SSH_HOST }}
          username: root
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            APP_DIR="/home/deploy/sites/mb-grid-solutions.com"
            mkdir -p $APP_DIR
            cd $APP_DIR
            
            # Update Environment
            cat > ${{ needs.prepare.outputs.env_file }} << EOF
            IMAGE_TAG=${{ needs.prepare.outputs.image_tag }}
            TRAEFIK_HOST=${{ needs.prepare.outputs.traefik_host }}
            PROJECT_NAME=${{ needs.prepare.outputs.project_name }}
            NEXT_PUBLIC_BASE_URL=${{ needs.prepare.outputs.next_public_base_url }}
            
            # Directus
            DIRECTUS_URL=${{ needs.prepare.outputs.directus_url }}
            DIRECTUS_HOST=${{ needs.prepare.outputs.directus_host }}
            DIRECTUS_API_TOKEN=${{ secrets.DIRECTUS_API_TOKEN }}
            DIRECTUS_ADMIN_EMAIL=${{ secrets.DIRECTUS_ADMIN_EMAIL || 'admin@mintel.me' }}
            DIRECTUS_ADMIN_PASSWORD=${{ secrets.DIRECTUS_ADMIN_PASSWORD }}
            DIRECTUS_DB_NAME=${{ secrets.DIRECTUS_DB_NAME || 'directus' }}
            DIRECTUS_DB_USER=${{ secrets.DIRECTUS_DB_USER || 'directus' }}
            DIRECTUS_DB_PASSWORD=${{ secrets.DIRECTUS_DB_PASSWORD }}
            DIRECTUS_KEY=${{ secrets.DIRECTUS_KEY }}
            DIRECTUS_SECRET=${{ secrets.DIRECTUS_SECRET }}
            EOF
            
            # Sync docker-compose
            echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
            docker compose -p "${{ needs.prepare.outputs.project_name }}" --env-file ${{ needs.prepare.outputs.env_file }} pull
            docker compose -p "${{ needs.prepare.outputs.project_name }}" --env-file ${{ needs.prepare.outputs.env_file }} up -d --remove-orphans
            docker system prune -f --filter "until=24h"

  notifications:
    name: 🔔 Notifications
    needs: [prepare, deploy]
    if: always()
    runs-on: docker
    container:
      image: catthehacker/ubuntu:act-latest
    steps:
      - name: Notify Gotify
        shell: bash
        run: |
          STATUS="${{ needs.deploy.result }}"
          COLOR="info"
          [[ "$STATUS" == "success" ]] && PRIORITY=5 || PRIORITY=8
          
          curl -X POST "${{ secrets.GOTIFY_URL }}/message?token=${{ secrets.GOTIFY_TOKEN }}" \
            -F "title=mb-grid-solutions Deployment" \
            -F "message=Status: $STATUS for ${{ needs.prepare.outputs.target }} (${{ needs.prepare.outputs.image_tag }})" \
            -F "priority=$PRIORITY"
