# =============================================================================
# Turnstone Docker Compose Stack
#
# Usage:
#   Default (SQLite):     docker compose up
#   Production (PG):      DB_BACKEND=postgresql docker compose --profile production up
#                         (or set DB_BACKEND=postgresql in .env)
#   10-node cluster:      docker compose --profile cluster up
#   With simulator:       docker compose --profile sim up
# =============================================================================

name: turnstone

networks:
  turnstone-net:
    driver: bridge

volumes:
  redis-data:
  turnstone-data:
  postgres-data:

services:
  # -------------------------------------------------------------------
  # PostgreSQL — production database (profile: production)
  # -------------------------------------------------------------------
  postgres:
    image: postgres:17-alpine
    profiles:
      - production
      - cluster
    environment:
      POSTGRES_DB: turnstone
      POSTGRES_USER: ${POSTGRES_USER:-turnstone}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required for production profile}
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - turnstone-net
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-turnstone}"]
      interval: 5s
      timeout: 3s
      retries: 5
      start_period: 5s
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: '1.0'
    restart: unless-stopped

  # -------------------------------------------------------------------
  # Redis — message broker, pub/sub, node registry
  # -------------------------------------------------------------------
  redis:
    image: redis:7.4-alpine
    command:
      - sh
      - -c
      - >-
        redis-server
        --save 60 1
        --loglevel warning
        $${REDIS_PASSWORD:+--requirepass $$REDIS_PASSWORD}
    ports:
      - "${REDIS_PORT:-6379}:6379"
    environment:
      - REDIS_PASSWORD=${REDIS_PASSWORD:-}
    volumes:
      - redis-data:/data
    networks:
      - turnstone-net
    healthcheck:
      test:
        - CMD-SHELL
        - redis-cli $${REDIS_PASSWORD:+-a $$REDIS_PASSWORD} ping | grep -q PONG
      interval: 5s
      timeout: 3s
      retries: 5
      start_period: 5s
    restart: unless-stopped

  # -------------------------------------------------------------------
  # turnstone-server — Web UI + chat workstreams + LLM interaction
  # -------------------------------------------------------------------
  server:
    build:
      context: .
      dockerfile: Dockerfile
    command:
      - sh
      - -c
      - >-
        turnstone-server
        --host 0.0.0.0
        --port 8080
        --base-url "$${LLM_BASE_URL}"
        --api-key "$${OPENAI_API_KEY}"
        $${MODEL:+--model $$MODEL}
        $${SKIP_PERMISSIONS:+--skip-permissions}
    ports:
      - "${SERVER_PORT:-8080}:8080"
    volumes:
      - turnstone-data:/data
    environment:
      - LLM_BASE_URL=${LLM_BASE_URL:-http://host.docker.internal:8000/v1}
      - OPENAI_API_KEY=${OPENAI_API_KEY:-dummy}
      - TAVILY_API_KEY=${TAVILY_API_KEY:-}
      - SKIP_PERMISSIONS=${SKIP_PERMISSIONS:-}
      - TURNSTONE_AUTH_ENABLED=${TURNSTONE_AUTH_ENABLED:-}
      - TURNSTONE_AUTH_TOKEN=${TURNSTONE_AUTH_TOKEN:-}
      - TURNSTONE_JWT_SECRET=${TURNSTONE_JWT_SECRET:-}
      - MODEL=${MODEL:-}
      - TURNSTONE_DB_BACKEND=${DB_BACKEND:-sqlite}
      - TURNSTONE_DB_URL=${DATABASE_URL:-}
      - TURNSTONE_NODE_ID=${TURNSTONE_NODE_ID:-}
    extra_hosts:
      - "host.docker.internal:host-gateway"
    networks:
      - turnstone-net
    depends_on:
      redis:
        condition: service_healthy
      postgres:
        condition: service_healthy
        required: false
    healthcheck:
      test: ["CMD", "python", "/usr/local/bin/healthcheck.py", "http://127.0.0.1:8080/health"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 15s
    restart: unless-stopped

  # -------------------------------------------------------------------
  # turnstone-bridge — Redis <-> HTTP bridge for multi-node routing
  # Node ID auto-generated from container hostname (no --node-id needed)
  # -------------------------------------------------------------------
  bridge:
    build:
      context: .
      dockerfile: Dockerfile
    command:
      - turnstone-bridge
      - --server-url=http://server:8080
      - --redis-host=redis
      - --redis-port=6379
      - --heartbeat-ttl=${HEARTBEAT_TTL:-60}
      - --approval-timeout=${APPROVAL_TIMEOUT:-3600}
    environment:
      - REDIS_PASSWORD=${REDIS_PASSWORD:-}
      - TURNSTONE_AUTH_TOKEN=${TURNSTONE_AUTH_TOKEN:-}
      - TURNSTONE_JWT_SECRET=${TURNSTONE_JWT_SECRET:-}
    networks:
      - turnstone-net
    depends_on:
      server:
        condition: service_healthy
      redis:
        condition: service_healthy
    restart: unless-stopped

  # -------------------------------------------------------------------
  # turnstone-console — Cluster dashboard
  # -------------------------------------------------------------------
  console:
    build:
      context: .
      dockerfile: Dockerfile
    command:
      - turnstone-console
      - --host=0.0.0.0
      - --port=8090
      - --redis-host=redis
      - --redis-port=6379
      - --poll-interval=${CONSOLE_POLL_INTERVAL:-10}
    ports:
      - "${CONSOLE_PORT:-8090}:8090"
    environment:
      - REDIS_PASSWORD=${REDIS_PASSWORD:-}
      - TURNSTONE_AUTH_ENABLED=${TURNSTONE_AUTH_ENABLED:-}
      - TURNSTONE_AUTH_TOKEN=${TURNSTONE_AUTH_TOKEN:-}
      - TURNSTONE_JWT_SECRET=${TURNSTONE_JWT_SECRET:-}
      - TURNSTONE_DB_BACKEND=${DB_BACKEND:-sqlite}
      - TURNSTONE_DB_URL=${DATABASE_URL:-}
    networks:
      - turnstone-net
    depends_on:
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "python", "/usr/local/bin/healthcheck.py", "http://127.0.0.1:8090/health"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 10s
    restart: unless-stopped

  # -------------------------------------------------------------------
  # turnstone-channel — Channel gateway (Discord, Slack, etc.)
  # Requires TURNSTONE_DISCORD_TOKEN to enable Discord adapter
  # -------------------------------------------------------------------
  channel:
    build:
      context: .
      dockerfile: Dockerfile
    profiles:
      - production
      - cluster
    command:
      - sh
      - -c
      - >-
        turnstone-channel
        --redis-host=redis
        --redis-port=6379
        --http-host=0.0.0.0
        $${TURNSTONE_DISCORD_GUILD:+--discord-guild $$TURNSTONE_DISCORD_GUILD}
    environment:
      - TURNSTONE_DISCORD_TOKEN=${TURNSTONE_DISCORD_TOKEN:-}
      - TURNSTONE_DISCORD_GUILD=${TURNSTONE_DISCORD_GUILD:-0}
      - REDIS_PASSWORD=${REDIS_PASSWORD:-}
      - TURNSTONE_JWT_SECRET=${TURNSTONE_JWT_SECRET:-}
      - TURNSTONE_DB_BACKEND=${DB_BACKEND:-sqlite}
      - TURNSTONE_DB_URL=${DATABASE_URL:-}
      - TURNSTONE_CHANNEL_ADVERTISE_URL=http://channel:8091
    networks:
      - turnstone-net
    depends_on:
      redis:
        condition: service_healthy
      postgres:
        condition: service_healthy
        required: false
    restart: unless-stopped

  # -------------------------------------------------------------------
  # turnstone-sim — Multi-node cluster simulator (no LLM needed)
  # Start with: docker compose --profile sim up
  # -------------------------------------------------------------------
  sim:
    build:
      context: .
      dockerfile: Dockerfile
    profiles:
      - sim
    command:
      - sh
      - -c
      - >-
        turnstone-sim
        --nodes "$${SIM_NODES}"
        --scenario "$${SIM_SCENARIO}"
        --duration "$${SIM_DURATION}"
        --mps "$${SIM_MPS}"
        --redis-host redis
        --redis-port 6379
        --log-level "$${SIM_LOG_LEVEL}"
        $${SIM_SEED:+--seed $$SIM_SEED}
        $${SIM_METRICS_FILE:+--metrics-file $$SIM_METRICS_FILE}
    environment:
      - REDIS_PASSWORD=${REDIS_PASSWORD:-}
      - SIM_NODES=${SIM_NODES:-100}
      - SIM_SCENARIO=${SIM_SCENARIO:-steady}
      - SIM_DURATION=${SIM_DURATION:-60}
      - SIM_MPS=${SIM_MPS:-5.0}
      - SIM_LOG_LEVEL=${SIM_LOG_LEVEL:-INFO}
      - SIM_SEED=${SIM_SEED:-}
      - SIM_METRICS_FILE=${SIM_METRICS_FILE:-}
    networks:
      - turnstone-net
    depends_on:
      redis:
        condition: service_healthy
    restart: "no"

  # ===================================================================
  # 10-node cluster (profile: cluster)
  #
  # Each node is a server + bridge pair.  All share the same PostgreSQL
  # and Redis instances.  Access via console at :8090.
  #
  # Start:  docker compose --profile cluster up
  # ===================================================================

  # -- cluster servers ------------------------------------------------

  server-1: &cluster-server
    build: { context: ., dockerfile: Dockerfile }
    profiles: [cluster]
    command: &cluster-server-cmd
      - sh
      - -c
      - >-
        turnstone-server
        --host 0.0.0.0
        --port 8080
        --base-url "$${LLM_BASE_URL}"
        --api-key "$${OPENAI_API_KEY}"
        $${MODEL:+--model $$MODEL}
        $${SKIP_PERMISSIONS:+--skip-permissions}
    volumes: [turnstone-data:/data]
    environment: &cluster-server-env
      LLM_BASE_URL: ${LLM_BASE_URL:-http://host.docker.internal:8000/v1}
      OPENAI_API_KEY: ${OPENAI_API_KEY:-dummy}
      TAVILY_API_KEY: ${TAVILY_API_KEY:-}
      SKIP_PERMISSIONS: ${SKIP_PERMISSIONS:-}
      TURNSTONE_AUTH_ENABLED: ${TURNSTONE_AUTH_ENABLED:-}
      TURNSTONE_AUTH_TOKEN: ${TURNSTONE_AUTH_TOKEN:-}
      TURNSTONE_JWT_SECRET: ${TURNSTONE_JWT_SECRET:-}
      MODEL: ${MODEL:-}
      TURNSTONE_DB_BACKEND: ${DB_BACKEND:-postgresql}
      TURNSTONE_DB_URL: ${DATABASE_URL:-postgresql://${POSTGRES_USER:-turnstone}:${POSTGRES_PASSWORD:?}@postgres:5432/turnstone}
      TURNSTONE_NODE_ID: node-1
    extra_hosts: ["host.docker.internal:host-gateway"]
    networks: [turnstone-net]
    depends_on:
      redis: { condition: service_healthy }
      postgres: { condition: service_healthy }
    healthcheck:
      test: ["CMD", "python", "/usr/local/bin/healthcheck.py", "http://127.0.0.1:8080/health"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 15s
    deploy:
      resources:
        limits: { memory: 384M, cpus: '0.5' }
    restart: unless-stopped

  server-2:
    <<: *cluster-server
    environment: { <<: *cluster-server-env, TURNSTONE_NODE_ID: node-2 }
  server-3:
    <<: *cluster-server
    environment: { <<: *cluster-server-env, TURNSTONE_NODE_ID: node-3 }
  server-4:
    <<: *cluster-server
    environment: { <<: *cluster-server-env, TURNSTONE_NODE_ID: node-4 }
  server-5:
    <<: *cluster-server
    environment: { <<: *cluster-server-env, TURNSTONE_NODE_ID: node-5 }
  server-6:
    <<: *cluster-server
    environment: { <<: *cluster-server-env, TURNSTONE_NODE_ID: node-6 }
  server-7:
    <<: *cluster-server
    environment: { <<: *cluster-server-env, TURNSTONE_NODE_ID: node-7 }
  server-8:
    <<: *cluster-server
    environment: { <<: *cluster-server-env, TURNSTONE_NODE_ID: node-8 }
  server-9:
    <<: *cluster-server
    environment: { <<: *cluster-server-env, TURNSTONE_NODE_ID: node-9 }
  server-10:
    <<: *cluster-server
    environment: { <<: *cluster-server-env, TURNSTONE_NODE_ID: node-10 }

  # -- cluster bridges ------------------------------------------------

  bridge-1: &cluster-bridge
    build: { context: ., dockerfile: Dockerfile }
    profiles: [cluster]
    command:
      - turnstone-bridge
      - --server-url=http://server-1:8080
      - --redis-host=redis
      - --redis-port=6379
      - --heartbeat-ttl=${HEARTBEAT_TTL:-60}
      - --approval-timeout=${APPROVAL_TIMEOUT:-3600}
    environment: &cluster-bridge-env
      REDIS_PASSWORD: ${REDIS_PASSWORD:-}
      TURNSTONE_AUTH_TOKEN: ${TURNSTONE_AUTH_TOKEN:-}
      TURNSTONE_JWT_SECRET: ${TURNSTONE_JWT_SECRET:-}
    networks: [turnstone-net]
    depends_on:
      server-1: { condition: service_healthy }
      redis: { condition: service_healthy }
    deploy:
      resources:
        limits: { memory: 256M, cpus: '0.25' }
    restart: unless-stopped

  bridge-2:
    <<: *cluster-bridge
    command:
      - turnstone-bridge
      - --server-url=http://server-2:8080
      - --redis-host=redis
      - --redis-port=6379
      - --heartbeat-ttl=${HEARTBEAT_TTL:-60}
      - --approval-timeout=${APPROVAL_TIMEOUT:-3600}
    depends_on:
      server-2: { condition: service_healthy }
      redis: { condition: service_healthy }
  bridge-3:
    <<: *cluster-bridge
    command:
      - turnstone-bridge
      - --server-url=http://server-3:8080
      - --redis-host=redis
      - --redis-port=6379
      - --heartbeat-ttl=${HEARTBEAT_TTL:-60}
      - --approval-timeout=${APPROVAL_TIMEOUT:-3600}
    depends_on:
      server-3: { condition: service_healthy }
      redis: { condition: service_healthy }
  bridge-4:
    <<: *cluster-bridge
    command:
      - turnstone-bridge
      - --server-url=http://server-4:8080
      - --redis-host=redis
      - --redis-port=6379
      - --heartbeat-ttl=${HEARTBEAT_TTL:-60}
      - --approval-timeout=${APPROVAL_TIMEOUT:-3600}
    depends_on:
      server-4: { condition: service_healthy }
      redis: { condition: service_healthy }
  bridge-5:
    <<: *cluster-bridge
    command:
      - turnstone-bridge
      - --server-url=http://server-5:8080
      - --redis-host=redis
      - --redis-port=6379
      - --heartbeat-ttl=${HEARTBEAT_TTL:-60}
      - --approval-timeout=${APPROVAL_TIMEOUT:-3600}
    depends_on:
      server-5: { condition: service_healthy }
      redis: { condition: service_healthy }
  bridge-6:
    <<: *cluster-bridge
    command:
      - turnstone-bridge
      - --server-url=http://server-6:8080
      - --redis-host=redis
      - --redis-port=6379
      - --heartbeat-ttl=${HEARTBEAT_TTL:-60}
      - --approval-timeout=${APPROVAL_TIMEOUT:-3600}
    depends_on:
      server-6: { condition: service_healthy }
      redis: { condition: service_healthy }
  bridge-7:
    <<: *cluster-bridge
    command:
      - turnstone-bridge
      - --server-url=http://server-7:8080
      - --redis-host=redis
      - --redis-port=6379
      - --heartbeat-ttl=${HEARTBEAT_TTL:-60}
      - --approval-timeout=${APPROVAL_TIMEOUT:-3600}
    depends_on:
      server-7: { condition: service_healthy }
      redis: { condition: service_healthy }
  bridge-8:
    <<: *cluster-bridge
    command:
      - turnstone-bridge
      - --server-url=http://server-8:8080
      - --redis-host=redis
      - --redis-port=6379
      - --heartbeat-ttl=${HEARTBEAT_TTL:-60}
      - --approval-timeout=${APPROVAL_TIMEOUT:-3600}
    depends_on:
      server-8: { condition: service_healthy }
      redis: { condition: service_healthy }
  bridge-9:
    <<: *cluster-bridge
    command:
      - turnstone-bridge
      - --server-url=http://server-9:8080
      - --redis-host=redis
      - --redis-port=6379
      - --heartbeat-ttl=${HEARTBEAT_TTL:-60}
      - --approval-timeout=${APPROVAL_TIMEOUT:-3600}
    depends_on:
      server-9: { condition: service_healthy }
      redis: { condition: service_healthy }
  bridge-10:
    <<: *cluster-bridge
    command:
      - turnstone-bridge
      - --server-url=http://server-10:8080
      - --redis-host=redis
      - --redis-port=6379
      - --heartbeat-ttl=${HEARTBEAT_TTL:-60}
      - --approval-timeout=${APPROVAL_TIMEOUT:-3600}
    depends_on:
      server-10: { condition: service_healthy }
      redis: { condition: service_healthy }
