name: CI

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

permissions:
  contents: read
  pages: write
  id-token: write
  packages: write

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: niklasrosenstein/rise
  BUILDER_IMAGE_NAME: niklasrosenstein/rise-builder

# NOTE: Rust toolchain version (1.91.1) must be kept in sync with mise.toml
# See: https://github.com/jdx/mise-action/issues/215

jobs:
  sqlx-check:
    name: Verify SQLX offline query data
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Rust toolchain
        uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: "1.91.1"

      - name: Setup mise
        uses: jdx/mise-action@v2
        with:
          cache: true
          tools: cargo:sqlx-cli

      - name: Check SQLX offline data is up to date
        run: mise run sqlx:check

  fmt:
    name: Check code formatting
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Rust toolchain
        uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: "1.91.1"
          components: rustfmt

      - name: Check formatting
        run: cargo fmt --all -- --check

  clippy:
    name: Lint with Clippy
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Rust toolchain
        uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: "1.91.1"
          components: clippy

      - name: Setup mise
        uses: jdx/mise-action@v2
        with:
          cache: true
          tools: cargo:cargo-all-features

      - name: Run Clippy (all feature combinations)
        run: cargo all-features clippy --all-targets -- -D warnings
        env:
          SQLX_OFFLINE: true

  test:
    name: Run tests
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: rise_test
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Rust toolchain
        uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: "1.91.1"

      - name: Setup mise
        uses: jdx/mise-action@v2
        with:
          cache: true
          tools: cargo:sqlx-cli

      - name: Run database migrations
        run: |
          sqlx database create
          sqlx migrate run
        env:
          DATABASE_URL: postgres://postgres:postgres@localhost:5432/rise_test

      - name: Run tests
        run: cargo test --all-features
        env:
          DATABASE_URL: postgres://postgres:postgres@localhost:5432/rise_test

  build:
    name: Build all targets
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Rust toolchain
        uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: "1.91.1"

      - name: Setup mise
        uses: jdx/mise-action@v2
        with:
          cache: true
          tools: cargo:cargo-all-features

      - name: Build all targets (all feature combinations)
        run: cargo all-features build --all-targets
        env:
          SQLX_OFFLINE: true

  helm-lint:
    name: Lint Helm charts
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup mise
        uses: jdx/mise-action@v2
        with:
          cache: true
          tools: helm

      - name: Set up chart-testing
        uses: helm/chart-testing-action@v2.6.1

      - name: Run chart-testing (lint)
        run: ct lint --target-branch ${{ github.event.repository.default_branch }} --charts helm/rise --validate-maintainers=false

  # helm-test:
  #   name: Test Helm charts
  #   runs-on: ubuntu-latest
  #   if: github.event_name == 'pull_request'
  #   needs: helm-lint
  #   steps:
  #     - name: Checkout repository
  #       uses: actions/checkout@v4
  #       with:
  #         fetch-depth: 0

  #     - name: Setup mise
  #       uses: jdx/mise-action@v2
  #       with:
  #         cache: true
  #         tools: helm

  #     - name: Set up chart-testing
  #       uses: helm/chart-testing-action@v2.6.1

  #     - name: Create kind cluster
  #       uses: helm/kind-action@v1.10.0

  #     - name: Run chart-testing (install)
  #       run: ct install --target-branch ${{ github.event.repository.default_branch }} --charts helm/rise

  helm-package:
    name: Package Helm charts
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    needs: helm-lint
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup mise
        uses: jdx/mise-action@v2
        with:
          cache: true
          tools: helm

      - name: Package Helm chart
        run: helm package helm/rise -d .helm-packages

      - name: Upload Helm chart package
        uses: actions/upload-artifact@v4
        with:
          name: helm-chart
          path: .helm-packages/*.tgz

  docs-build:
    name: Build documentation
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup mise
        uses: jdx/mise-action@v2
        with:
          cache: true
          tools: cargo:mdbook

      - name: Build book
        run: mdbook build

      - name: Setup Pages
        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
        uses: actions/configure-pages@v4

      - name: Upload artifact
        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
        uses: actions/upload-pages-artifact@v3
        with:
          path: './book'

  docs-deploy:
    name: Deploy documentation
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    needs: docs-build
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

  docker-build:
    name: Build and push Docker images
    runs-on: ubuntu-latest
    if: github.event_name == 'push' || startsWith(github.ref, 'refs/tags/v')
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

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

      - name: Log in to GitHub Container Registry
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=semver,pattern={{major}}
            type=sha,prefix=sha-
            type=raw,value=latest,enable={{is_default_branch}}

      - name: Build and push Docker image
        id: build
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./Dockerfile
          target: rise
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: |
            type=gha
            type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
          cache-to: |
            type=gha,mode=max
            type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
          platforms: linux/amd64
          provenance: false

      - name: Output build results
        run: |
          echo "Image digest: ${{ steps.build.outputs.digest }}"
          echo "Build completed successfully!"

      - name: Extract metadata (tags, labels) for Builder Docker image
        id: meta-builder
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.BUILDER_IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=semver,pattern={{major}}
            type=sha,prefix=sha-
            type=raw,value=latest,enable={{is_default_branch}}

      - name: Build and push Builder Docker image
        id: build-builder
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./Dockerfile
          target: rise-builder
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta-builder.outputs.tags }}
          labels: ${{ steps.meta-builder.outputs.labels }}
          cache-from: |
            type=gha
            type=registry,ref=${{ env.REGISTRY }}/${{ env.BUILDER_IMAGE_NAME }}:buildcache
          cache-to: |
            type=gha,mode=max
            type=registry,ref=${{ env.REGISTRY }}/${{ env.BUILDER_IMAGE_NAME }}:buildcache,mode=max
          platforms: linux/amd64
          provenance: false

      - name: Output builder build results
        run: |
          echo "Builder image digest: ${{ steps.build-builder.outputs.digest }}"
          echo "Builder build completed successfully!"

  publish-crates:
    name: Publish to crates.io
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/v')
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Rust toolchain
        uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: "1.91.1"

      - name: Verify version matches tag
        run: |
          TAG_VERSION=${GITHUB_REF#refs/tags/v}
          CARGO_VERSION=$(cargo metadata --format-version=1 --no-deps | jq -r '.packages[0].version')
          echo "Tag version: $TAG_VERSION"
          echo "Cargo version: $CARGO_VERSION"
          if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
            echo "::error::Tag version ($TAG_VERSION) doesn't match Cargo version ($CARGO_VERSION)"
            exit 1
          fi

      - name: Authenticate with crates.io
        uses: rust-lang/crates-io-auth-action@v1
        id: auth

      - name: Publish to crates.io
        run: cargo publish --features cli
        env:
          CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
