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

ROOT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
cd "$ROOT_DIR"

BACKEND_DIR="${BACKEND_DIR:-$ROOT_DIR/backend}"
FRONTEND_DIR="${FRONTEND_DIR:-$ROOT_DIR/frontend}"
RUN_DIR="${RUN_DIR:-$BACKEND_DIR/.run}"

START_REDIS="${START_REDIS:-1}"
START_RABBITMQ="${START_RABBITMQ:-1}"
START_BACKEND="${START_BACKEND:-1}"
START_WORKER="${START_WORKER:-1}"
START_FRONTEND="${START_FRONTEND:-1}"

# docker compose (for dependencies like RabbitMQ):
# - START_RABBITMQ=1|0 (default 1)
# - COMPOSE_FILE=path (default ./docker-compose.yml)
# - STOP_DOCKER=1|0 (default 0; when 1, stop started compose services on exit)
COMPOSE_FILE="${COMPOSE_FILE:-$ROOT_DIR/docker-compose.yml}"
STOP_DOCKER="${STOP_DOCKER:-0}"

# frontend:
# - FRONTEND_INSTALL=auto|1|0 (default auto, only when node_modules missing)
# - FRONTEND_SCRIPT=dev|preview|build (default dev)
FRONTEND_INSTALL="${FRONTEND_INSTALL:-auto}"
FRONTEND_SCRIPT="${FRONTEND_SCRIPT:-dev}"

# backend:
# - CONFIG_PATH can override the backend config. When this script also starts
#   compose dependencies, default to the compose-local config that uses host
#   port 3307 for MySQL.
if [ -z "${CONFIG_PATH:-}" ] && [ "$START_RABBITMQ" = "1" ]; then
  CONFIG_PATH="configs/config.compose-local.yaml"
fi
export CONFIG_PATH

# redis:
# - If you already run Redis elsewhere, this will detect it (when redis-cli exists) and skip.
REDIS_HOST="${REDIS_HOST:-127.0.0.1}"
REDIS_PORT="${REDIS_PORT:-6379}"
REDIS_CONF="${REDIS_CONF:-}"

require_dir() {
  if [ ! -d "$2" ]; then
    echo "[start.sh] $1 dir not found: $2"
    exit 1
  fi
}

require_cmd() {
  if ! command -v "$1" >/dev/null 2>&1; then
    echo "[start.sh] command not found: $1"
    exit 1
  fi
}

BACKEND_PID=""
WORKER_PID=""
FRONTEND_PID=""
cleanup() {
  set +e
  if [ -n "${FRONTEND_PID:-}" ]; then
    echo "[start.sh] Stopping frontend (pid=$FRONTEND_PID)"
    kill "$FRONTEND_PID" >/dev/null 2>&1 || true
  fi
  if [ -n "${WORKER_PID:-}" ]; then
    echo "[start.sh] Stopping worker (pid=$WORKER_PID)"
    kill "$WORKER_PID" >/dev/null 2>&1 || true
  fi
  if [ -n "${BACKEND_PID:-}" ]; then
    echo "[start.sh] Stopping backend (pid=$BACKEND_PID)"
    kill "$BACKEND_PID" >/dev/null 2>&1 || true
  fi
  # On Windows Git Bash, child processes sometimes don't receive signals reliably.
  # Fall back to taskkill when available.
  if command -v taskkill >/dev/null 2>&1; then
    if [ -n "${FRONTEND_PID:-}" ]; then
      taskkill //PID "$FRONTEND_PID" //T //F >/dev/null 2>&1 || true
    fi
    if [ -n "${WORKER_PID:-}" ]; then
      taskkill //PID "$WORKER_PID" //T //F >/dev/null 2>&1 || true
    fi
    if [ -n "${BACKEND_PID:-}" ]; then
      taskkill //PID "$BACKEND_PID" //T //F >/dev/null 2>&1 || true
    fi
  fi

  if [ "$STOP_DOCKER" = "1" ] && [ -n "${COMPOSE_CMD:-}" ] && [ -f "$COMPOSE_FILE" ]; then
    echo "[start.sh] Stopping docker compose services"
    $COMPOSE_CMD -f "$COMPOSE_FILE" stop >/dev/null 2>&1 || true
  fi
}
trap cleanup INT TERM EXIT

if [ "$START_BACKEND" = "1" ] || [ "$START_WORKER" = "1" ]; then
  require_dir backend "$BACKEND_DIR"
  mkdir -p "$RUN_DIR"
  require_cmd go
fi

if [ "$START_FRONTEND" = "1" ]; then
  require_dir frontend "$FRONTEND_DIR"
  mkdir -p "$RUN_DIR"
  require_cmd npm
fi

detect_compose() {
  if command -v docker >/dev/null 2>&1; then
    if docker compose version >/dev/null 2>&1; then
      COMPOSE_CMD="docker compose"
      return 0
    fi
  fi
  if command -v docker-compose >/dev/null 2>&1; then
    COMPOSE_CMD="docker-compose"
    return 0
  fi
  return 1
}

start_rabbitmq_compose() {
  if [ ! -f "$COMPOSE_FILE" ]; then
    echo "[start.sh] $COMPOSE_FILE not found; skip starting RabbitMQ via docker compose"
    return 0
  fi
  if ! detect_compose; then
    echo "[start.sh] docker compose not found; skip starting RabbitMQ via docker compose"
    return 0
  fi

  echo "[start.sh] Starting RabbitMQ via docker compose ($COMPOSE_FILE)"
  $COMPOSE_CMD -f "$COMPOSE_FILE" up -d rabbitmq

  # Best-effort readiness check.
  if command -v docker >/dev/null 2>&1; then
    local rabbit_cid=""
    rabbit_cid="$($COMPOSE_CMD -f "$COMPOSE_FILE" ps -q rabbitmq 2>/dev/null || true)"
    if [ -z "$rabbit_cid" ]; then
      rabbit_cid="my-rabbitmq"
    fi

    local i=0
    while [ "$i" -lt 30 ]; do
      if docker exec "$rabbit_cid" rabbitmq-diagnostics -q ping >/dev/null 2>&1; then
        echo "[start.sh] RabbitMQ ready"
        return 0
      fi
      sleep 1
      i=$((i + 1))
    done
    echo "[start.sh] RabbitMQ may not be ready yet; continuing anyway"
  fi
}

start_redis() {
  if ! command -v redis-server >/dev/null 2>&1; then
    echo "[start.sh] redis-server not found; skip starting Redis"
    return 0
  fi

  if command -v redis-cli >/dev/null 2>&1; then
    if redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" ping >/dev/null 2>&1; then
      echo "[start.sh] Redis already running at $REDIS_HOST:$REDIS_PORT"
      return 0
    fi
  fi

  echo "[start.sh] Starting Redis at $REDIS_HOST:$REDIS_PORT"
  if [ -n "$REDIS_CONF" ]; then
    nohup redis-server "$REDIS_CONF" >"$RUN_DIR/redis.log" 2>&1 &
  else
    nohup redis-server --bind "$REDIS_HOST" --port "$REDIS_PORT" >"$RUN_DIR/redis.log" 2>&1 &
  fi
  echo $! >"$RUN_DIR/redis.pid"
}

start_backend_bg() {
  echo "[start.sh] Starting backend (background)"
  (cd "$BACKEND_DIR" && go run ./cmd) &
  BACKEND_PID=$!
  echo "$BACKEND_PID" >"$RUN_DIR/backend.pid"
  echo "[start.sh] Backend PID: $BACKEND_PID"
}

start_worker_bg() {
  echo "[start.sh] Starting worker (background)"
  (cd "$BACKEND_DIR" && go run ./cmd/worker) &
  WORKER_PID=$!
  echo "$WORKER_PID" >"$RUN_DIR/worker.pid"
  echo "[start.sh] Worker PID: $WORKER_PID"
}

start_frontend_bg() {
  if [ "$FRONTEND_INSTALL" = "1" ] || { [ "$FRONTEND_INSTALL" = "auto" ] && [ ! -d "$FRONTEND_DIR/node_modules" ]; }; then
    echo "[start.sh] Installing frontend deps"
    (cd "$FRONTEND_DIR" && npm install)
  fi

  echo "[start.sh] Starting frontend (background, npm run $FRONTEND_SCRIPT)"
  (cd "$FRONTEND_DIR" && npm run "$FRONTEND_SCRIPT") &
  FRONTEND_PID=$!
  echo "$FRONTEND_PID" >"$RUN_DIR/frontend.pid"
  echo "[start.sh] Frontend PID: $FRONTEND_PID"
}

if [ "$START_RABBITMQ" = "1" ] && { [ "$START_BACKEND" = "1" ] || [ "$START_WORKER" = "1" ]; }; then
  start_rabbitmq_compose
fi

if [ "$START_REDIS" = "1" ] && { [ "$START_BACKEND" = "1" ] || [ "$START_WORKER" = "1" ]; }; then
  start_redis
fi

if [ "$START_BACKEND" = "1" ]; then
  start_backend_bg
fi

if [ "$START_WORKER" = "1" ]; then
  start_worker_bg
fi

if [ "$START_FRONTEND" = "1" ]; then
  start_frontend_bg
fi

if [ "$START_BACKEND" = "1" ] || [ "$START_WORKER" = "1" ] || [ "$START_FRONTEND" = "1" ]; then
  echo "[start.sh] Press Ctrl+C to stop."
  wait
else
  echo "[start.sh] Nothing to start. Set START_BACKEND=1 and/or START_WORKER=1 and/or START_FRONTEND=1."
fi
