# GitLab CI/CD Pipeline for Qrusty Priority Queue System
# This pipeline builds, tests, generates documentation, and creates Docker images

stages:
  - build
  - test
  - examples
  - docs
  - security
  - package

# Include security scanning templates
include:
  - template: Security/SAST.gitlab-ci.yml
  - template: Security/Secret-Detection.gitlab-ci.yml

variables:
  CARGO_HOME: "$CI_PROJECT_DIR/.cargo"
  SECRET_DETECTION_ENABLED: "true"
  SAST_ENABLED: "true"
  # Help libclang detection for RocksDB native bindings - platform agnostic
  BINDGEN_EXTRA_CLANG_ARGS: "-I/usr/include"

# Cache cargo dependencies for faster builds
.rust_cache: &rust_cache
  cache:
    key:
      files:
        - Cargo.lock
        - Cargo.toml
    paths:
      - .cargo/
      - target/release/deps/
      - target/debug/deps/
      - target/release/build/
      - target/debug/build/

# Base template for Rust jobs with native dependencies
.rust_job: &rust_job
  image: rust:latest
  <<: *rust_cache
  before_script:
    - apt-get update -qq
    - apt-get install -y -qq build-essential cmake clang libclang-dev pkg-config
    - |
      # Dynamically detect libclang path for current architecture
      ARCH=$(uname -m)
      if [ "$ARCH" = "x86_64" ]; then
        export LIBCLANG_PATH="/usr/lib/x86_64-linux-gnu"
      elif [ "$ARCH" = "aarch64" ]; then
        export LIBCLANG_PATH="/usr/lib/aarch64-linux-gnu"
      else
        # Fallback: try to find libclang dynamically
        export LIBCLANG_PATH=$(find /usr/lib -name "libclang.so*" 2>/dev/null | head -1 | xargs dirname)
      fi
      echo "Architecture: $ARCH"
      echo "Using libclang path: $LIBCLANG_PATH"
    - rustc --version
    - cargo --version

# Build the project
build:
  <<: *rust_job
  stage: build
  script:
    - cargo build --verbose
    - cargo build --release --verbose
  artifacts:
    paths:
      - target/release/qrusty
      - target/release/libqrusty.rlib
    expire_in: 1 hour

# Run all tests including examples
test:
  <<: *rust_job
  stage: test
  needs:
    - job: "build"
      optional: true
  before_script:
    - apt-get update -qq
    - apt-get install -y -qq build-essential cmake clang libclang-dev pkg-config python3
    - |
      # Dynamically detect libclang path for current architecture
      ARCH=$(uname -m)
      if [ "$ARCH" = "x86_64" ]; then
        export LIBCLANG_PATH="/usr/lib/x86_64-linux-gnu"
      elif [ "$ARCH" = "aarch64" ]; then
        export LIBCLANG_PATH="/usr/lib/aarch64-linux-gnu"
      else
        # Fallback: try to find libclang dynamically
        export LIBCLANG_PATH=$(find /usr/lib -name "libclang.so*" 2>/dev/null | head -1 | xargs dirname)
      fi
      echo "Architecture: $ARCH"
      echo "Using libclang path: $LIBCLANG_PATH"
    - rustc --version
    - cargo --version
    - python3 --version
  script:
    - echo "Running comprehensive test suite including examples..."
    # Note: 'make all' includes build, doc, machete, test, and examples
    - make all
    - cargo test --doc --verbose
  coverage: '/^\s*lines:\s*\d+\.\d+\%/'
  artifacts:
    reports:
      junit: target/test-results.xml
    expire_in: 1 hour

# Generate and publish documentation
docs:
  <<: *rust_job
  stage: docs
  needs:
    - job: "build"
      optional: true
  script:
    - cargo doc --no-deps --verbose
  artifacts:
    paths:
      - target/doc/
    expire_in: 1 week
  only:
    - main
    - merge_requests

# Lint and format check
lint:
  <<: *rust_job
  stage: test
  needs:
    - job: "build"
      optional: true
  before_script:
    - apt-get update -qq
    - apt-get install -y -qq build-essential cmake clang libclang-dev pkg-config
    - rustup component add rustfmt clippy
    - rustc --version
    - cargo --version
  script:
    - cargo fmt -- --check
    - cargo clippy -- -D warnings
  allow_failure: true

# Validate integration examples (dedicated stage for visibility)
examples:
  <<: *rust_job
  stage: examples
  needs:
    - job: "build"
      optional: true
  before_script:
    - apt-get update -qq
    - apt-get install -y -qq build-essential cmake clang libclang-dev pkg-config python3
    - |
      # Dynamically detect libclang path for current architecture
      ARCH=$(uname -m)
      if [ "$ARCH" = "x86_64" ]; then
        export LIBCLANG_PATH="/usr/lib/x86_64-linux-gnu"
      elif [ "$ARCH" = "aarch64" ]; then
        export LIBCLANG_PATH="/usr/lib/aarch64-linux-gnu"
      else
        # Fallback: try to find libclang dynamically
        export LIBCLANG_PATH=$(find /usr/lib -name "libclang.so*" 2>/dev/null | head -1 | xargs dirname)
      fi
      echo "Architecture: $ARCH"
      echo "Using libclang path: $LIBCLANG_PATH"
    - rustc --version
    - cargo --version
    - python3 --version
  script:
    - echo "Validating all integration examples..."
    # Note: This provides dedicated visibility for example validation
    # Examples are also tested as part of 'make all' in the test stage
    - make examples
  artifacts:
    reports:
      junit: target/example-results.xml
    expire_in: 1 hour

# Security scanning - SAST
sast:
  stage: security
  needs:
    - job: "build"
      optional: true
  variables:
    SAST_EXCLUDED_PATHS: "target/"

# Secret detection
secret_detection:
  stage: security

# Build Docker image
docker_build:
  stage: package
  image: docker:latest
  services:
    - docker:dind
  needs:
    - job: "test"
      optional: true
    - job: "docs"
      optional: true
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker build -t $CI_REGISTRY_IMAGE:latest .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - docker push $CI_REGISTRY_IMAGE:latest
  only:
    - main
    - tags

# Build Docker image for merge requests (without pushing)
docker_build_mr:
  stage: package
  image: docker:latest
  services:
    - docker:dind
  needs:
    - job: "test"
      optional: true
  script:
    - docker build -t qrusty:test .
  only:
    - merge_requests
