#!/usr/bin/env bash
set -euo pipefail

# ---------------------------------------------------------------------------
# build-and-push.sh - Build and push service images to Scaleway registry
# ---------------------------------------------------------------------------
# Builds all Foxhunt service Docker images and pushes to the Scaleway
# Container Registry. Supports parallel builds, selective service builds,
# and sccache for faster compilation.
#
# Usage:
#   ./infra/scripts/build-and-push.sh                  # Build & push all
#   ./infra/scripts/build-and-push.sh --no-push        # Build only
#   ./infra/scripts/build-and-push.sh --services "api-gateway trading-service"
#   ./infra/scripts/build-and-push.sh --parallel 3     # 3 concurrent builds
#   ./infra/scripts/build-and-push.sh --dry-run        # Show what would run
# ---------------------------------------------------------------------------

REGISTRY="rg.fr-par.scw.cloud"
NAMESPACE="foxhunt"
GIT_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
TIMESTAMP=$(date -u +"%Y%m%d-%H%M%S")

# Services built with Dockerfile.service (--build-arg SERVICE=<name>)
STANDARD_SERVICES=(
  api
  trading-service
  trading-agent-service
  ml-training-service
  backtesting-service
  broker-gateway
)

# Defaults
DO_PUSH=true
DRY_RUN=false
PARALLEL=1
SELECTED_SERVICES=()
SKIP_STANDARD=false
SKIP_TRAINING=false
TAG_LATEST=true

usage() {
  cat <<EOF
Usage: $(basename "$0") [OPTIONS]

Options:
  --no-push              Build only, don't push to registry
  --dry-run              Show what would be built
  --services "s1 s2"     Build only these standard services
  --skip-training        Skip training image build
  --parallel N           Run N builds concurrently (default: 1)
  --no-latest            Don't tag images as :latest
  -h, --help             Show this help
EOF
}

while [[ $# -gt 0 ]]; do
  case $1 in
    --no-push)        DO_PUSH=false; shift ;;
    --dry-run)        DRY_RUN=true; shift ;;
    --services)       IFS=' ' read -ra SELECTED_SERVICES <<< "$2"; shift 2 ;;
    --skip-training)  SKIP_TRAINING=true; shift ;;
    --parallel)       PARALLEL="$2"; shift 2 ;;
    --no-latest)      TAG_LATEST=false; shift ;;
    -h|--help)        usage; exit 0 ;;
    *)                echo "Unknown option: $1"; usage; exit 1 ;;
  esac
done

# If --services was given, use only those; otherwise use all standard services
if [[ ${#SELECTED_SERVICES[@]} -gt 0 ]]; then
  SERVICES=("${SELECTED_SERVICES[@]}")
  SKIP_TRAINING=true
else
  SERVICES=("${STANDARD_SERVICES[@]}")
fi

# Dirty check
if ! git diff-index --quiet HEAD -- 2>/dev/null; then
  GIT_COMMIT="${GIT_COMMIT}-dirty"
fi

TAG_COMMIT="${GIT_COMMIT}"
TAG_TS="${TIMESTAMP}"

echo "=== Foxhunt Docker Build ==="
echo "Registry:  ${REGISTRY}/${NAMESPACE}"
echo "Commit:    ${TAG_COMMIT}"
echo "Timestamp: ${TAG_TS}"
echo "Parallel:  ${PARALLEL}"
echo ""

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

PASS=0
FAIL=0
FAILURES=()

build_and_tag() {
  local image_name="$1"
  local dockerfile="$2"
  shift 2
  local extra_args=("$@")

  local full="${REGISTRY}/${NAMESPACE}/${image_name}"

  local tags=("-t" "${full}:${TAG_COMMIT}" "-t" "${full}:${TAG_TS}")
  if [[ "$TAG_LATEST" == "true" ]]; then
    tags+=("-t" "${full}:latest")
  fi

  local cmd=(docker build "${tags[@]}" -f "$dockerfile" "${extra_args[@]}" .)

  if [[ "$DRY_RUN" == "true" ]]; then
    echo "  [DRY] ${cmd[*]}"
    return 0
  fi

  echo "  Building ${image_name}..."
  local start
  start=$(date +%s)

  if DOCKER_BUILDKIT=1 "${cmd[@]}" 2>&1 | tail -5; then
    local elapsed=$(( $(date +%s) - start ))
    echo "  [OK] ${image_name} (${elapsed}s)"
    (( PASS++ ))
  else
    echo "  [FAIL] ${image_name}"
    (( FAIL++ ))
    FAILURES+=("${image_name}")
    return 1
  fi
}

push_image() {
  local image_name="$1"
  local full="${REGISTRY}/${NAMESPACE}/${image_name}"

  for tag in "${TAG_COMMIT}" "${TAG_TS}" $( [[ "$TAG_LATEST" == "true" ]] && echo "latest" ); do
    if [[ "$DRY_RUN" == "true" ]]; then
      echo "  [DRY] docker push ${full}:${tag}"
    else
      echo "  Pushing ${full}:${tag}"
      docker push "${full}:${tag}"
    fi
  done
}

# ---------------------------------------------------------------------------
# Ensure registry login
# ---------------------------------------------------------------------------

if [[ "$DRY_RUN" != "true" && "$DO_PUSH" == "true" ]]; then
  echo "--- Registry Login ---"
  if ! docker login "${REGISTRY}" -u nologin --password-stdin <<< "$(scw registry login -o json 2>/dev/null | python3 -c 'import sys,json; print(json.load(sys.stdin).get("password",""))' 2>/dev/null)" 2>/dev/null; then
    echo "  Trying scw registry login..."
    scw registry login
  fi
  echo ""
fi

# ---------------------------------------------------------------------------
# Build standard services (Dockerfile.service)
# ---------------------------------------------------------------------------

echo "--- Standard Services ---"

if [[ "$PARALLEL" -gt 1 ]]; then
  # Parallel builds using background jobs
  PIDS=()
  for svc in "${SERVICES[@]}"; do
    (
      build_and_tag "$svc" "infra/docker/Dockerfile.service" --build-arg "SERVICE=${svc}"
    ) &
    PIDS+=($!)
    # Throttle to PARALLEL concurrent jobs
    while [[ $(jobs -r | wc -l) -ge $PARALLEL ]]; do
      sleep 1
    done
  done
  # Wait for all builds
  for pid in "${PIDS[@]}"; do
    wait "$pid" || (( FAIL++ ))
  done
else
  for svc in "${SERVICES[@]}"; do
    build_and_tag "$svc" "infra/docker/Dockerfile.service" --build-arg "SERVICE=${svc}" || true
  done
fi

# ---------------------------------------------------------------------------
# Build training image (Dockerfile.training)
# ---------------------------------------------------------------------------

if [[ "$SKIP_TRAINING" != "true" ]]; then
  echo ""
  echo "--- Training Image ---"
  build_and_tag "training" "infra/docker/Dockerfile.training" || true
fi

# ---------------------------------------------------------------------------
# Push
# ---------------------------------------------------------------------------

if [[ "$DO_PUSH" == "true" ]]; then
  echo ""
  echo "--- Pushing Images ---"

  for svc in "${SERVICES[@]}"; do
    push_image "$svc"
  done

  if [[ "$SKIP_TRAINING" != "true" ]]; then
    push_image "training"
  fi
fi

# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------

echo ""
echo "======================================================================"
printf "  Results: %d built, %d failed\n" "$PASS" "$FAIL"
echo "======================================================================"

if [[ $FAIL -gt 0 ]]; then
  echo ""
  echo "  Failed:"
  for f in "${FAILURES[@]}"; do
    echo "    - ${f}"
  done
  echo ""
  exit 1
fi

echo ""
echo "  All images built successfully."
if [[ "$DO_PUSH" == "true" && "$DRY_RUN" != "true" ]]; then
  echo "  Pushed to: ${REGISTRY}/${NAMESPACE}/"
fi
exit 0
