# =============================================================================
# Prax ORM - Docker Compose for Testing
# =============================================================================
# Usage:
#   docker compose up -d              # Start all databases
#   docker compose up -d postgres     # Start only PostgreSQL
#   docker compose run test           # Run all tests
#   docker compose run test-postgres  # Run PostgreSQL tests only
#   docker compose down -v            # Stop and remove volumes

name: prax

services:
  # ===========================================================================
  # Database Services
  # ===========================================================================

  postgres:
    image: pgvector/pgvector:pg16
    container_name: prax-postgres
    environment:
      POSTGRES_USER: prax
      POSTGRES_PASSWORD: prax_test_password
      POSTGRES_DB: prax_test
    ports:
      - "5433:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./docker/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U prax -d prax_test"]
      interval: 5s
      timeout: 5s
      retries: 5
    network_mode: host

  mysql:
    image: mysql:8.0
    container_name: prax-mysql
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_USER: prax
      MYSQL_PASSWORD: prax_test_password
      MYSQL_DATABASE: prax_test
      MYSQL_TCP_PORT: 3307
    ports:
      - "3307:3307"
    volumes:
      - mysql_data:/var/lib/mysql
      - ./docker/mysql/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    command: --default-authentication-plugin=mysql_native_password --port=3307
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-P", "3307", "-u", "prax", "-pprax_test_password"]
      interval: 5s
      timeout: 5s
      retries: 10
    network_mode: host

  mssql:
    image: mcr.microsoft.com/mssql/server:2022-latest
    container_name: prax-mssql
    environment:
      ACCEPT_EULA: "Y"
      MSSQL_SA_PASSWORD: "Prax_Test_Password123!"
      MSSQL_PID: "Developer"
    ports:
      - "1433:1433"
    volumes:
      - mssql_data:/var/opt/mssql
      - ./docker/mssql/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
      - ./docker/mssql/setup.sh:/docker-entrypoint-initdb.d/setup.sh:ro
    healthcheck:
      test: ["CMD-SHELL", "/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'Prax_Test_Password123!' -C -Q 'SELECT 1' || exit 1"]
      interval: 10s
      timeout: 10s
      retries: 10
      start_period: 30s
    network_mode: host

  mongodb:
    image: mongo:7.0
    container_name: prax-mongodb
    environment:
      MONGO_INITDB_ROOT_USERNAME: prax
      MONGO_INITDB_ROOT_PASSWORD: prax_test_password
      MONGO_INITDB_DATABASE: prax_test
    ports:
      - "27017:27017"
    volumes:
      - mongodb_data:/data/db
      - ./docker/mongodb/init.js:/docker-entrypoint-initdb.d/init.js:ro
    healthcheck:
      test: ["CMD", "mongosh", "--quiet", "-u", "prax", "-p", "prax_test_password", "--authenticationDatabase", "admin", "--eval", "db.adminCommand('ping')"]
      interval: 10s
      timeout: 10s
      retries: 5
      start_period: 30s
    network_mode: host

  # ScyllaDB - high-throughput Cassandra-compatible DB. Binds 9042 on the host.
  scylladb:
    image: scylladb/scylla:5.4
    container_name: prax-scylladb
    # Developer mode relaxes kernel tunables Scylla normally enforces; --smp/
    # --memory keep the footprint small in CI.
    command:
      - --smp
      - "1"
      - --memory
      - 1G
      - --overprovisioned
      - "1"
      - --developer-mode
      - "1"
    volumes:
      - scylladb_data:/var/lib/scylla
    healthcheck:
      test: ["CMD-SHELL", "cqlsh -e 'SELECT now() FROM system.local' >/dev/null 2>&1 || exit 1"]
      interval: 10s
      timeout: 10s
      retries: 20
      start_period: 60s
    network_mode: host

  # Apache Cassandra. Runs native transport on 9043 to avoid clashing with
  # ScyllaDB on 9042 (both services share the host network namespace).
  cassandra:
    image: cassandra:5.0
    container_name: prax-cassandra
    environment:
      CASSANDRA_CLUSTER_NAME: PraxTestCluster
      HEAP_NEWSIZE: 128M
      MAX_HEAP_SIZE: 1G
      JVM_EXTRA_OPTS: "-Dcassandra.native_transport_port=9043"
    volumes:
      - cassandra_data:/var/lib/cassandra
    healthcheck:
      test:
        - "CMD-SHELL"
        - "cqlsh -e 'SELECT now() FROM system.local' localhost 9043 >/dev/null 2>&1 || exit 1"
      interval: 15s
      timeout: 10s
      retries: 25
      start_period: 90s
    network_mode: host

  # ===========================================================================
  # Test Runner Services
  # ===========================================================================

  # Run all tests against all databases (including E2E integration tests)
  test:
    build:
      context: .
      target: test-runner
    container_name: prax-test
    environment:
      POSTGRES_URL: postgres://prax:prax_test_password@localhost:5432/prax_test
      MYSQL_URL: mysql://prax:prax_test_password@localhost:3307/prax_test
      MSSQL_URL: "mssql://sa:Prax_Test_Password123!@localhost:1433/prax_test?TrustServerCertificate=true"
      MONGODB_URL: "mongodb://prax:prax_test_password@localhost:27017/prax_test?authSource=admin"
      SQLITE_URL: file:./test.db
      DUCKDB_URL: "duckdb::memory:"
      SCYLLA_URL: "scylla://localhost:9042/prax_test"
      CASSANDRA_URL: "cassandra://localhost:9043/prax_test"
      # E2E toggle — tests skip themselves unless this is set, so the
      # default `cargo test` outside compose stays fast and hermetic.
      PRAX_E2E: "1"
      RUST_BACKTRACE: 1
      RUST_LOG: info
    depends_on:
      postgres:
        condition: service_healthy
      mysql:
        condition: service_healthy
      mssql:
        condition: service_healthy
      mongodb:
        condition: service_healthy
      scylladb:
        condition: service_healthy
      cassandra:
        condition: service_healthy
    volumes:
      - cargo_cache:/usr/local/cargo/registry
      - target_cache:/app/target
    network_mode: host
    # Note: we do NOT pass `--all-features` at the workspace level because
    # `prax-mssql` exposes mutually-exclusive `rustls` and `native-tls`
    # features (both cannot compile together under tiberius). Per-crate
    # runners below opt into `--all-features` individually.
    command: cargo test --workspace -- --include-ignored

  # Run PostgreSQL tests only
  test-postgres:
    build:
      context: .
      target: test-runner
    container_name: prax-test-postgres
    environment:
      DATABASE_URL: postgres://prax:prax_test_password@localhost:5432/prax_test
      POSTGRES_URL: postgres://prax:prax_test_password@localhost:5432/prax_test
      PRAX_E2E: "1"
      RUST_BACKTRACE: 1
    depends_on:
      postgres:
        condition: service_healthy
    volumes:
      - cargo_cache:/usr/local/cargo/registry
      - target_cache:/app/target
    network_mode: host
    command: cargo test -p prax-postgres --all-features -- --include-ignored

  # Run MySQL tests only
  test-mysql:
    build:
      context: .
      target: test-runner
    container_name: prax-test-mysql
    environment:
      DATABASE_URL: mysql://prax:prax_test_password@localhost:3307/prax_test
      MYSQL_URL: mysql://prax:prax_test_password@localhost:3307/prax_test
      PRAX_E2E: "1"
      RUST_BACKTRACE: 1
    depends_on:
      mysql:
        condition: service_healthy
    volumes:
      - cargo_cache:/usr/local/cargo/registry
      - target_cache:/app/target
    network_mode: host
    command: cargo test -p prax-mysql --all-features -- --include-ignored

  # Run SQLite tests only (no external dependencies)
  test-sqlite:
    build:
      context: .
      target: test-runner
    container_name: prax-test-sqlite
    environment:
      DATABASE_URL: file:./test.db
      SQLITE_URL: file:./test.db
      PRAX_E2E: "1"
      RUST_BACKTRACE: 1
    volumes:
      - cargo_cache:/usr/local/cargo/registry
      - target_cache:/app/target
    network_mode: host
    command: cargo test -p prax-sqlite --all-features -- --include-ignored

  # Run MSSQL tests only
  test-mssql:
    build:
      context: .
      target: test-runner
    container_name: prax-test-mssql
    environment:
      DATABASE_URL: "mssql://sa:Prax_Test_Password123!@localhost:1433/prax_test?TrustServerCertificate=true"
      MSSQL_URL: "mssql://sa:Prax_Test_Password123!@localhost:1433/prax_test?TrustServerCertificate=true"
      PRAX_E2E: "1"
      RUST_BACKTRACE: 1
    depends_on:
      mssql:
        condition: service_healthy
    volumes:
      - cargo_cache:/usr/local/cargo/registry
      - target_cache:/app/target
    network_mode: host
    # NOTE: `--all-features` is omitted here because the `rustls` and
    # `native-tls` features are mutually exclusive tiberius TLS backends.
    # Default features (`rustls`) are sufficient for E2E coverage.
    command: cargo test -p prax-mssql -- --include-ignored

  # Run pgvector tests only
  test-pgvector:
    build:
      context: .
      target: test-runner
    container_name: prax-test-pgvector
    environment:
      DATABASE_URL: postgres://prax:prax_test_password@localhost:5432/prax_test
      POSTGRES_URL: postgres://prax:prax_test_password@localhost:5432/prax_test
      PRAX_E2E: "1"
      RUST_BACKTRACE: 1
    depends_on:
      postgres:
        condition: service_healthy
    volumes:
      - cargo_cache:/usr/local/cargo/registry
      - target_cache:/app/target
    network_mode: host
    command: cargo test -p prax-pgvector --all-features -- --ignored

  # Run MongoDB tests only
  test-mongodb:
    build:
      context: .
      target: test-runner
    container_name: prax-test-mongodb
    environment:
      DATABASE_URL: "mongodb://prax:prax_test_password@localhost:27017/prax_test?authSource=admin"
      MONGODB_URL: "mongodb://prax:prax_test_password@localhost:27017/prax_test?authSource=admin"
      PRAX_E2E: "1"
      RUST_BACKTRACE: 1
    depends_on:
      mongodb:
        condition: service_healthy
    volumes:
      - cargo_cache:/usr/local/cargo/registry
      - target_cache:/app/target
    network_mode: host
    command: cargo test -p prax-mongodb --all-features -- --include-ignored

  # Run DuckDB tests only — embedded, no external service needed.
  test-duckdb:
    build:
      context: .
      target: test-runner
    container_name: prax-test-duckdb
    environment:
      DUCKDB_URL: "duckdb::memory:"
      PRAX_E2E: "1"
      RUST_BACKTRACE: 1
    volumes:
      - cargo_cache:/usr/local/cargo/registry
      - target_cache:/app/target
    network_mode: host
    command: cargo test -p prax-duckdb --all-features -- --include-ignored

  # Run ScyllaDB tests only
  test-scylladb:
    build:
      context: .
      target: test-runner
    container_name: prax-test-scylladb
    environment:
      SCYLLA_URL: "scylla://localhost:9042/prax_test"
      PRAX_E2E: "1"
      RUST_BACKTRACE: 1
    depends_on:
      scylladb:
        condition: service_healthy
    volumes:
      - cargo_cache:/usr/local/cargo/registry
      - target_cache:/app/target
    network_mode: host
    command: cargo test -p prax-scylladb --all-features -- --include-ignored

  # Run Cassandra tests only — gated behind the `cassandra-live` feature.
  # NOTE: prax-cassandra's engine methods are currently stubbed (see
  # prax-cassandra/src/engine.rs). E2E coverage today is limited to a
  # cdrs-tokio reachability smoke test; expand once engine is wired.
  test-cassandra:
    build:
      context: .
      target: test-runner
    container_name: prax-test-cassandra
    environment:
      CASSANDRA_URL: "cassandra://localhost:9043/prax_test"
      PRAX_E2E: "1"
      RUST_BACKTRACE: 1
    depends_on:
      cassandra:
        condition: service_healthy
    volumes:
      - cargo_cache:/usr/local/cargo/registry
      - target_cache:/app/target
    network_mode: host
    command: cargo test -p prax-cassandra --features cassandra-live -- --include-ignored

  # ===========================================================================
  # Development Service
  # ===========================================================================

  dev:
    build:
      context: .
      target: development
    container_name: prax-dev
    environment:
      POSTGRES_URL: postgres://prax:prax_test_password@localhost:5432/prax_test
      MYSQL_URL: mysql://prax:prax_test_password@localhost:3307/prax_test
      SQLITE_URL: file:./dev.db
      RUST_BACKTRACE: 1
      RUST_LOG: debug
    depends_on:
      - postgres
      - mysql
    volumes:
      - .:/app
      - cargo_cache:/usr/local/cargo/registry
      - target_cache:/app/target
    network_mode: host
    stdin_open: true
    tty: true
    command: bash

  # ===========================================================================
  # Benchmark Service
  # ===========================================================================

  bench:
    build:
      context: .
      target: test-runner
    container_name: prax-bench
    environment:
      POSTGRES_URL: postgres://prax:prax_test_password@localhost:5432/prax_test
      MYSQL_URL: mysql://prax:prax_test_password@localhost:3307/prax_test
      SQLITE_URL: file:./bench.db
    depends_on:
      postgres:
        condition: service_healthy
      mysql:
        condition: service_healthy
    volumes:
      - cargo_cache:/usr/local/cargo/registry
      - target_cache:/app/target
      - ./target/criterion:/app/target/criterion
    network_mode: host
    command: cargo bench --workspace

  # ===========================================================================
  # Coverage Service
  # ===========================================================================

  coverage:
    build:
      context: .
      target: test-runner
    container_name: prax-coverage
    environment:
      POSTGRES_URL: postgres://prax:prax_test_password@localhost:5432/prax_test
      MYSQL_URL: mysql://prax:prax_test_password@localhost:3307/prax_test
      SQLITE_URL: file:./coverage.db
      RUST_BACKTRACE: 1
    depends_on:
      postgres:
        condition: service_healthy
      mysql:
        condition: service_healthy
    volumes:
      - cargo_cache:/usr/local/cargo/registry
      - target_cache:/app/target
      - ./coverage:/app/coverage
    network_mode: host
    command: >
      sh -c "cargo llvm-cov --workspace --html --output-dir /app/coverage"

# =============================================================================
# Volumes
# =============================================================================

volumes:
  postgres_data:
    name: prax-postgres-data
  mysql_data:
    name: prax-mysql-data
  mssql_data:
    name: prax-mssql-data
  mongodb_data:
    name: prax-mongodb-data
  scylladb_data:
    name: prax-scylladb-data
  cassandra_data:
    name: prax-cassandra-data
  cargo_cache:
    name: prax-cargo-cache
  target_cache:
    name: prax-target-cache
