name: Backend CI/CD Pipeline

on:
  push:
    branches: [master, main]
    paths:
      - 'maternal-app-backend/**'
      - '.github/workflows/backend-ci.yml'
  pull_request:
    branches: [master, main]
    paths:
      - 'maternal-app-backend/**'
      - '.github/workflows/backend-ci.yml'

jobs:
  lint-and-test:
    name: Lint and Test Backend
    runs-on: ubuntu-latest

    defaults:
      run:
        working-directory: maternal-app/maternal-app-backend

    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_USER: testuser
          POSTGRES_PASSWORD: testpassword
          POSTGRES_DB: maternal_test
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

      redis:
        image: redis:7-alpine
        ports:
          - 6379:6379
        options: >-
          --health-cmd "redis-cli ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

      mongodb:
        image: mongo:7
        ports:
          - 27017:27017
        options: >-
          --health-cmd "mongosh --eval 'db.adminCommand(\"ping\")'"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

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

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
          cache-dependency-path: maternal-app/maternal-app-backend/package-lock.json

      - name: Install dependencies
        run: npm ci

      - name: Run linter
        run: npm run lint

      - name: Run unit tests
        run: npm run test:cov
        env:
          DATABASE_HOST: localhost
          DATABASE_PORT: 5432
          DATABASE_USER: testuser
          DATABASE_PASSWORD: testpassword
          DATABASE_NAME: maternal_test
          REDIS_HOST: localhost
          REDIS_PORT: 6379
          MONGODB_URI: mongodb://localhost:27017/maternal_test
          JWT_SECRET: test-jwt-secret-key-for-ci
          JWT_REFRESH_SECRET: test-refresh-secret-key-for-ci
          OPENAI_API_KEY: test-api-key

      - name: Upload coverage reports
        uses: codecov/codecov-action@v4
        with:
          directory: maternal-app/maternal-app-backend/coverage
          flags: backend
          fail_ci_if_error: false

      - name: Check coverage thresholds
        run: |
          COVERAGE=$(npm run test:cov -- --silent | grep 'All files' | awk '{print $4}' | sed 's/%//')
          echo "Current coverage: ${COVERAGE}%"
          if (( $(echo "$COVERAGE < 70" | bc -l) )); then
            echo "::warning::Coverage ${COVERAGE}% is below 70% threshold"
          fi

  e2e-tests:
    name: E2E Tests Backend
    runs-on: ubuntu-latest
    needs: lint-and-test

    defaults:
      run:
        working-directory: maternal-app/maternal-app-backend

    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_USER: testuser
          POSTGRES_PASSWORD: testpassword
          POSTGRES_DB: maternal_test
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

      redis:
        image: redis:7-alpine
        ports:
          - 6379:6379
        options: >-
          --health-cmd "redis-cli ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

      mongodb:
        image: mongo:7
        ports:
          - 27017:27017
        options: >-
          --health-cmd "mongosh --eval 'db.adminCommand(\"ping\")'"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

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

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
          cache-dependency-path: maternal-app/maternal-app-backend/package-lock.json

      - name: Install dependencies
        run: npm ci

      - name: Run database migrations
        run: npm run migration:run
        env:
          DATABASE_HOST: localhost
          DATABASE_PORT: 5432
          DATABASE_USER: testuser
          DATABASE_PASSWORD: testpassword
          DATABASE_NAME: maternal_test

      - name: Run E2E tests
        run: npm run test:e2e
        env:
          DATABASE_HOST: localhost
          DATABASE_PORT: 5432
          DATABASE_USER: testuser
          DATABASE_PASSWORD: testpassword
          DATABASE_NAME: maternal_test
          REDIS_HOST: localhost
          REDIS_PORT: 6379
          MONGODB_URI: mongodb://localhost:27017/maternal_test
          JWT_SECRET: test-jwt-secret-key-for-ci
          JWT_REFRESH_SECRET: test-refresh-secret-key-for-ci
          OPENAI_API_KEY: test-api-key
          CI: true

      - name: Upload E2E test results
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: e2e-test-results
          path: maternal-app/maternal-app-backend/test-results/
          retention-days: 30

  build:
    name: Build Backend Application
    runs-on: ubuntu-latest
    needs: lint-and-test

    defaults:
      run:
        working-directory: maternal-app/maternal-app-backend

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

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
          cache-dependency-path: maternal-app/maternal-app-backend/package-lock.json

      - name: Install dependencies
        run: npm ci

      - name: Build application
        run: npm run build

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: backend-build
          path: maternal-app/maternal-app-backend/dist/
          retention-days: 7

  performance-test:
    name: Performance Testing
    runs-on: ubuntu-latest
    needs: build
    if: github.event_name == 'pull_request'

    defaults:
      run:
        working-directory: maternal-app/maternal-app-backend

    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_USER: testuser
          POSTGRES_PASSWORD: testpassword
          POSTGRES_DB: maternal_test
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

      redis:
        image: redis:7-alpine
        ports:
          - 6379:6379

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

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
          cache-dependency-path: maternal-app/maternal-app-backend/package-lock.json

      - name: Install dependencies
        run: npm ci

      - name: Download build artifacts
        uses: actions/download-artifact@v4
        with:
          name: backend-build
          path: maternal-app/maternal-app-backend/dist/

      - name: Start application
        run: |
          npm run start:prod &
          sleep 10
        env:
          DATABASE_HOST: localhost
          DATABASE_PORT: 5432
          DATABASE_USER: testuser
          DATABASE_PASSWORD: testpassword
          DATABASE_NAME: maternal_test
          REDIS_HOST: localhost
          REDIS_PORT: 6379
          JWT_SECRET: test-jwt-secret-key-for-ci
          JWT_REFRESH_SECRET: test-refresh-secret-key-for-ci
          PORT: 3000

      - name: Install Artillery
        run: npm install -g artillery@latest

      - name: Run performance tests
        run: |
          if [ -f "artillery.yml" ]; then
            artillery run artillery.yml --output performance-report.json
          else
            echo "::warning::No artillery.yml found, skipping performance tests"
          fi

      - name: Generate performance report
        if: always()
        run: |
          if [ -f "performance-report.json" ]; then
            artillery report performance-report.json --output performance-report.html
          fi

      - name: Upload performance report
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: performance-report
          path: |
            maternal-app/maternal-app-backend/performance-report.json
            maternal-app/maternal-app-backend/performance-report.html
          retention-days: 30
