name: Build and Deploy to Synology NAS

on:
  push:
    branches:
      - main
      - develop
  pull_request:
    branches:
      - main

env:
  DOCKER_IMAGE: laravel-app
  DOCKER_REGISTRY: ${{ secrets.SYNOLOGY_HOST }}:5000  # Synology Docker Registry Port

jobs:
  # Job 1: Run Tests
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          fetch-depth: 1

      - name: Validate Conventional Commit (subject line only)
        id: validate
        run: |
          SUBJECT="$(git log -1 --pretty=%s)"
          echo "Commit subject: $SUBJECT"
          if echo "$SUBJECT" | grep -Eq '^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)(\(.+\))?: .+'; then
            echo "valid=true" >> "$GITHUB_OUTPUT"
          else
            echo "valid=false" >> "$GITHUB_OUTPUT"
          fi

      - name: Setup PHP
        if: ${{ steps.validate.outputs.valid == 'true' }}
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.4'
          extensions: mbstring, xml, ctype, json, bcmath, pdo, pdo_sqlite
          coverage: none

      - name: Install Composer Dependencies
        if: ${{ steps.validate.outputs.valid == 'true' }}
        run: composer install --prefer-dist --no-progress --no-suggest

      - name: Setup Node.js
        if: ${{ steps.validate.outputs.valid == 'true' }}
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install NPM Dependencies
        if: ${{ steps.validate.outputs.valid == 'true' }}
        run: npm ci

      - name: Build Frontend Assets
        if: ${{ steps.validate.outputs.valid == 'true' }}
        run: npm run build

      - name: Run Tests
        if: ${{ steps.validate.outputs.valid == 'true' }}
        run: php artisan test --exclude-group=backend-db

  # Job 2: Build and Push Docker Image
  build:
    runs-on: ubuntu-latest
    needs: test
    if: github.event_name == 'push'

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Validate Conventional Commit
        id: validate
        run: |
          SUBJECT="$(git log -1 --pretty=%s)"
          echo "Commit subject: $SUBJECT"
          if echo "$SUBJECT" | grep -Eq '^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)(\(.+\))?: .+'; then
            echo "valid=true" >> "$GITHUB_OUTPUT"
          else
            echo "valid=false" >> "$GITHUB_OUTPUT"
          fi

      - name: Stop if not a Conventional Commit
        if: ${{ steps.validate.outputs.valid != 'true' }}
        run: |
          echo "Latest commit is not a valid Conventional Commit. Skipping build."
          exit 0

      - name: Set up Docker Buildx
        if: ${{ steps.validate.outputs.valid == 'true' }}
        uses: docker/setup-buildx-action@v3

      - name: Determine Docker Tag
        id: docker_tag
        if: ${{ steps.validate.outputs.valid == 'true' }}
        run: |
          if [ "${{ github.ref_name }}" == "main" ]; then
            echo "tag=latest" >> "$GITHUB_OUTPUT"
            echo "env=production" >> "$GITHUB_OUTPUT"
          else
            echo "tag=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
            echo "env=staging" >> "$GITHUB_OUTPUT"
          fi

      - name: Build Docker Image
        if: ${{ steps.validate.outputs.valid == 'true' }}
        uses: docker/build-push-action@v6
        with:
          context: .
          file: ./Dockerfile
          push: false
          load: true
          tags: ${{ env.DOCKER_IMAGE }}:${{ steps.docker_tag.outputs.tag }}

      - name: Save Docker Image
        if: ${{ steps.validate.outputs.valid == 'true' }}
        run: |
          docker save ${{ env.DOCKER_IMAGE }}:${{ steps.docker_tag.outputs.tag }} | gzip > laravel-app.tar.gz

      - name: Upload Docker Image Artifact
        if: ${{ steps.validate.outputs.valid == 'true' }}
        uses: actions/upload-artifact@v3
        with:
          name: docker-image
          path: laravel-app.tar.gz
          retention-days: 1

  # Job 3: Deploy to Synology NAS
  deploy:
    runs-on: ubuntu-latest
    needs: build
    if: github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'develop')

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Download Docker Image Artifact
        uses: actions/download-artifact@v3
        with:
          name: docker-image

      - name: Determine Environment
        id: env
        run: |
          if [ "${{ github.ref_name }}" == "main" ]; then
            echo "env=production" >> "$GITHUB_OUTPUT"
          else
            echo "env=staging" >> "$GITHUB_OUTPUT"
          fi

      - name: Setup SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SYNOLOGY_SSH_KEY }}" > ~/.ssh/synology_key
          chmod 600 ~/.ssh/synology_key
          # Disable strict host key checking for deployment
          cat >> ~/.ssh/config << 'EOF'
          Host *
            StrictHostKeyChecking no
            UserKnownHostsFile /dev/null
          EOF
          chmod 600 ~/.ssh/config

      - name: Copy Files to Synology
        run: |
          # Create directory if it doesn't exist
          ssh -i ~/.ssh/synology_key \
            ${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }} \
            "mkdir -p /volume1/docker/laravel-app"

          # Transfer Docker Image using cat over SSH
          cat laravel-app.tar.gz | ssh -i ~/.ssh/synology_key \
            ${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }} \
            "cat > /volume1/docker/laravel-app/laravel-app.tar.gz"

          # Transfer Docker Compose file
          cat docker-compose.synology.yml | ssh -i ~/.ssh/synology_key \
            ${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }} \
            "cat > /volume1/docker/laravel-app/docker-compose.synology.yml"

          # Transfer deployment script
          cat scripts/deploy-synology.sh | ssh -i ~/.ssh/synology_key \
            ${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }} \
            "cat > /volume1/docker/laravel-app/deploy-synology.sh"

      - name: Deploy on Synology
        run: |
          ssh -i ~/.ssh/synology_key \
            ${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }} \
            "cd /volume1/docker/laravel-app && chmod +x deploy-synology.sh && ./deploy-synology.sh"

      - name: Health Check
        run: |
          sleep 10  # Wait for container to start

          # Check if the app is responding
          SYNOLOGY_IP="${{ secrets.SYNOLOGY_HOST }}"
          MAX_RETRIES=30
          RETRY_COUNT=0

          while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
            if curl -f -s http://$SYNOLOGY_IP:8080/health > /dev/null 2>&1; then
              echo "✅ Application is healthy!"
              exit 0
            fi

            echo "⏳ Waiting for application to be ready... ($RETRY_COUNT/$MAX_RETRIES)"
            sleep 5
            RETRY_COUNT=$((RETRY_COUNT + 1))
          done

          echo "❌ Health check failed after $MAX_RETRIES attempts"
          exit 1

      - name: Cleanup
        if: always()
        run: |
          # Remove Docker image from Synology
          ssh -i ~/.ssh/synology_key \
            ${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }} \
            "rm -f /volume1/docker/laravel-app/laravel-app.tar.gz" || true
          # Remove SSH key
          rm -f ~/.ssh/synology_key

  # Job 4: Notify on Success/Failure (optional)
  notify:
    runs-on: ubuntu-latest
    needs: [test, build, deploy]
    if: always()

    steps:
      - name: Deployment Status
        run: |
          if [ "${{ needs.deploy.result }}" == "success" ]; then
            echo "✅ Deployment to Synology NAS successful!"
            echo "🌐 Application available at: http://${{ secrets.SYNOLOGY_HOST }}:8080"
          else
            echo "❌ Deployment failed. Check the logs for details."
            exit 1
          fi
