name: CI

on:
  push:
    branches: [main, develop, v2]
  pull_request:
    branches: [main, develop]

jobs:
  lint:
    runs-on: ubuntu-latest
    env:
      APT_CACHER_NG: http://192.168.88.14:3142
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: "3.12"

      # - name: Get pip cache dir
      #   id: pip-cache
      #   run: |
      #     echo "path=$(pip cache dir)" >> $GITEA_OUTPUT
      #     echo "Pip cache dir: $(pip cache dir)"

      # - name: Cache pip dependencies
      #   uses: actions/cache@v4
      #   with:
      #     path: ${{ steps.pip-cache.outputs.path }}
      #     key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt', 'requirements-test.txt', 'pyproject.toml') }}
      #     restore-keys: |
      #       ${{ runner.os }}-pip-

      - name: Configure apt proxy
        run: |
          if [ -n "${APT_CACHER_NG}" ]; then
            echo "Acquire::http::Proxy \"${APT_CACHER_NG}\";" | tee /etc/apt/apt.conf.d/01apt-cacher-ng
          fi

      - name: Install system packages
        run: |
          apt-get update
          apt-get install -y build-essential libpq-dev

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
          pip install -r requirements-test.txt

      - name: Run Ruff
        run: ruff check .

      - name: Run Black
        run: black --check .

      - name: Run Bandit
        run: bandit -c pyproject.toml -r tests

  test:
    runs-on: ubuntu-latest
    needs: lint
    env:
      APT_CACHER_NG: http://192.168.88.14:3142
      DB_DRIVER: postgresql+psycopg2
      DB_HOST: 192.168.88.35
      DB_NAME: calminer_test
      DB_USER: calminer
      DB_PASSWORD: calminer_password
    services:
      postgres:
        image: postgres:17
        env:
          POSTGRES_USER: ${{ env.DB_USER }}
          POSTGRES_PASSWORD: ${{ env.DB_PASSWORD }}
          POSTGRES_DB: ${{ env.DB_NAME }}
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: "3.12"

      # - name: Get pip cache dir
      #   id: pip-cache
      #   run: |
      #     echo "path=$(pip cache dir)" >> $GITEA_OUTPUT
      #     echo "Pip cache dir: $(pip cache dir)"

      # - name: Cache pip dependencies
      #   uses: actions/cache@v4
      #   with:
      #     path: ${{ steps.pip-cache.outputs.path }}
      #     key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt', 'requirements-test.txt', 'pyproject.toml') }}
      #     restore-keys: |
      #       ${{ runner.os }}-pip-

      - name: Configure apt proxy
        run: |
          if [ -n "${APT_CACHER_NG}" ]; then
            echo "Acquire::http::Proxy \"${APT_CACHER_NG}\";" | tee /etc/apt/apt.conf.d/01apt-cacher-ng
          fi

      - name: Install system packages
        run: |
          apt-get update
          apt-get install -y build-essential libpq-dev

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
          pip install -r requirements-test.txt

      - name: Install Playwright system dependencies
        run: playwright install-deps

      - name: Install Playwright browsers
        run: playwright install

      - name: Run tests
        env:
          DATABASE_DRIVER: ${{ env.DB_DRIVER }}
          DATABASE_HOST: postgres
          DATABASE_PORT: 5432
          DATABASE_USER: ${{ env.DB_USER }}
          DATABASE_PASSWORD: ${{ env.DB_PASSWORD }}
          DATABASE_NAME: ${{ env.DB_NAME }}
        run: |
          pytest --cov=. --cov-report=term-missing --cov-report=xml --cov-fail-under=80 --junitxml=pytest-report.xml

      - name: Upload test artifacts
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-artifacts
          path: |
            coverage.xml
            pytest-report.xml

  build:
    runs-on: ubuntu-latest
    needs:
      - lint
      - test
    env:
      DEFAULT_BRANCH: main
      REGISTRY_URL: ${{ secrets.REGISTRY_URL }}
      REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
      REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
      REGISTRY_CONTAINER_NAME: calminer
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Collect workflow metadata
        id: meta
        shell: bash
        run: |
          ref_name="${GITHUB_REF_NAME:-${GITHUB_REF##*/}}"
          event_name="${GITHUB_EVENT_NAME:-}"
          sha="${GITHUB_SHA:-}"

          if [ "$ref_name" = "${DEFAULT_BRANCH:-main}" ]; then
            echo "on_default=true" >> "$GITHUB_OUTPUT"
          else
            echo "on_default=false" >> "$GITHUB_OUTPUT"
          fi

          echo "ref_name=$ref_name" >> "$GITHUB_OUTPUT"
          echo "event_name=$event_name" >> "$GITHUB_OUTPUT"
          echo "sha=$sha" >> "$GITHUB_OUTPUT"

      - name: Set up QEMU and Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to gitea registry
        if: ${{ steps.meta.outputs.on_default == 'true' }}
        uses: docker/login-action@v3
        continue-on-error: true
        with:
          registry: ${{ env.REGISTRY_URL }}
          username: ${{ env.REGISTRY_USERNAME }}
          password: ${{ env.REGISTRY_PASSWORD }}

      - name: Build image
        id: build-image
        env:
          REGISTRY_URL: ${{ env.REGISTRY_URL }}
          REGISTRY_CONTAINER_NAME: ${{ env.REGISTRY_CONTAINER_NAME }}
          SHA_TAG: ${{ steps.meta.outputs.sha }}
          PUSH_IMAGE: ${{ steps.meta.outputs.on_default == 'true' && steps.meta.outputs.event_name != 'pull_request' && env.REGISTRY_URL != '' && env.REGISTRY_USERNAME != '' && env.REGISTRY_PASSWORD != '' }}
        run: |
          set -eo pipefail
          LOG_FILE=build.log
          if [ "${PUSH_IMAGE}" = "true" ]; then
            docker buildx build \
              --push \
              --tag "${REGISTRY_URL}/allucanget/${REGISTRY_CONTAINER_NAME}:latest" \
              --tag "${REGISTRY_URL}/allucanget/${REGISTRY_CONTAINER_NAME}:${SHA_TAG}" \
              --file Dockerfile \
              . 2>&1 | tee "${LOG_FILE}"
          else
            docker buildx build \
              --load \
              --tag "${REGISTRY_CONTAINER_NAME}:ci" \
              --file Dockerfile \
              . 2>&1 | tee "${LOG_FILE}"
          fi

      - name: Upload docker build logs
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: docker-build-logs
          path: build.log

  deploy:
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
    env:
      REGISTRY_URL: ${{ secrets.REGISTRY_URL }}
      REGISTRY_CONTAINER_NAME: calminer
      KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
      STAGING_KUBE_CONFIG: ${{ secrets.STAGING_KUBE_CONFIG }}
      PROD_KUBE_CONFIG: ${{ secrets.PROD_KUBE_CONFIG }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up kubectl for staging
        if: github.ref == 'refs/heads/main' && contains(github.event.head_commit.message, '[deploy staging]')
        uses: azure/k8s-set-context@v3
        with:
          method: kubeconfig
          kubeconfig: ${{ env.STAGING_KUBE_CONFIG }}

      - name: Set up kubectl for production
        if: github.ref == 'refs/heads/main' && contains(github.event.head_commit.message, '[deploy production]')
        uses: azure/k8s-set-context@v3
        with:
          method: kubeconfig
          kubeconfig: ${{ env.PROD_KUBE_CONFIG }}

      - name: Deploy to staging
        if: github.ref == 'refs/heads/main' && contains(github.event.head_commit.message, '[deploy staging]')
        run: |
          # Update image in deployment
          kubectl set image deployment/calminer-app calminer=${REGISTRY_URL}/allucanget/${REGISTRY_CONTAINER_NAME}:latest
          # Apply any config changes
          kubectl apply -f k8s/configmap.yaml
          kubectl apply -f k8s/secret.yaml
          # Wait for rollout
          kubectl rollout status deployment/calminer-app

      - name: Collect staging deployment logs
        if: github.ref == 'refs/heads/main' && contains(github.event.head_commit.message, '[deploy staging]')
        run: |
          mkdir -p logs/deployment/staging
          kubectl get pods -o wide > logs/deployment/staging/pods.txt
          kubectl get deployment calminer-app -o yaml > logs/deployment/staging/deployment.yaml
          kubectl logs deployment/calminer-app --all-containers=true --tail=500 > logs/deployment/staging/calminer-app.log

      - name: Deploy to production
        if: github.ref == 'refs/heads/main' && contains(github.event.head_commit.message, '[deploy production]')
        run: |
          # Update image in deployment
          kubectl set image deployment/calminer-app calminer=${REGISTRY_URL}/allucanget/${REGISTRY_CONTAINER_NAME}:latest
          # Apply any config changes
          kubectl apply -f k8s/configmap.yaml
          kubectl apply -f k8s/secret.yaml
          # Wait for rollout
          kubectl rollout status deployment/calminer-app

      - name: Collect production deployment logs
        if: github.ref == 'refs/heads/main' && contains(github.event.head_commit.message, '[deploy production]')
        run: |
          mkdir -p logs/deployment/production
          kubectl get pods -o wide > logs/deployment/production/pods.txt
          kubectl get deployment calminer-app -o yaml > logs/deployment/production/deployment.yaml
          kubectl logs deployment/calminer-app --all-containers=true --tail=500 > logs/deployment/production/calminer-app.log

      - name: Upload deployment logs
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: deployment-logs
          path: logs/deployment
          if-no-files-found: ignore
