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

PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CARGO_BIN="${MORAINE_CTL_CARGO:-cargo}"
CRATE_MANIFEST="$PROJECT_ROOT/apps/moraine/Cargo.toml"
BIN_PATH="$PROJECT_ROOT/target/debug/moraine"

build_binary() {
  local manifest_path="$1"
  "$CARGO_BIN" build --manifest-path "$manifest_path"
}

monitor_frontend_needs_build() {
  local dist_index="$PROJECT_ROOT/web/monitor/dist/index.html"
  if [[ ! -f "$dist_index" ]]; then
    return 0
  fi

  local watch_paths=(
    "$PROJECT_ROOT/web/monitor/src"
    "$PROJECT_ROOT/web/monitor/index.html"
    "$PROJECT_ROOT/web/monitor/package.json"
    "$PROJECT_ROOT/web/monitor/tsconfig.app.json"
    "$PROJECT_ROOT/web/monitor/tsconfig.node.json"
    "$PROJECT_ROOT/web/monitor/vite.config.ts"
  )

  local path
  for path in "${watch_paths[@]}"; do
    if [[ -d "$path" ]]; then
      if find "$path" -type f -newer "$dist_index" -print -quit | grep -q .; then
        return 0
      fi
    elif [[ -f "$path" && "$path" -nt "$dist_index" ]]; then
      return 0
    fi
  done

  return 1
}

has_flag() {
  local flag="$1"
  shift
  for arg in "$@"; do
    if [[ "$arg" == "$flag" || "$arg" == "$flag="* ]]; then
      return 0
    fi
  done
  return 1
}

resolve_config_path() {
  local config_path=""
  local skip_next=0
  local arg
  for arg in "$@"; do
    if [[ "$skip_next" == "1" ]]; then
      config_path="$arg"
      skip_next=0
      continue
    fi
    case "$arg" in
      --config)
        skip_next=1
        ;;
      --config=*)
        config_path="${arg#--config=}"
        ;;
    esac
  done

  if [[ -n "$config_path" ]]; then
    printf '%s\n' "$config_path"
    return 0
  fi

  if [[ -n "${MORAINE_CONFIG:-}" ]]; then
    printf '%s\n' "$MORAINE_CONFIG"
    return 0
  fi

  local home_cfg=""
  if [[ -n "${HOME:-}" ]]; then
    home_cfg="${HOME}/.moraine/config.toml"
    if [[ -f "$home_cfg" ]]; then
      printf '%s\n' "$home_cfg"
      return 0
    fi
  fi

  if [[ -f "$PROJECT_ROOT/config/moraine.toml" ]]; then
    printf '%s\n' "$PROJECT_ROOT/config/moraine.toml"
    return 0
  fi

  if [[ -n "$home_cfg" ]]; then
    printf '%s\n' "$home_cfg"
  else
    printf '%s\n' "$PROJECT_ROOT/config/moraine.toml"
  fi
}

monitor_enabled_for_up() {
  if has_flag "--monitor" "$@"; then
    return 0
  fi

  local cfg_path
  cfg_path="$(resolve_config_path "$@")"
  if [[ ! -f "$cfg_path" ]]; then
    # Runtime default in moraine-config is start_monitor_on_up=true.
    return 0
  fi

  local value=""
  value="$(
    awk '
      BEGIN { in_runtime = 0 }
      /^[[:space:]]*\[/ {
        in_runtime = ($0 ~ /^[[:space:]]*\[runtime\][[:space:]]*$/)
        next
      }
      in_runtime && /^[[:space:]]*start_monitor_on_up[[:space:]]*=/ {
        line = $0
        sub(/^[^=]*=[[:space:]]*/, "", line)
        sub(/[[:space:]]*(#.*)?$/, "", line)
        gsub(/"/, "", line)
        print tolower(line)
        exit
      }
    ' "$cfg_path"
  )"

  if [[ -z "$value" ]]; then
    return 0
  fi

  case "$value" in
    1|true|yes|on)
      return 0
      ;;
    0|false|no|off)
      return 1
      ;;
    *)
      return 0
      ;;
  esac
}

ensure_monitor_frontend() {
  local dist_dir="$PROJECT_ROOT/web/monitor/dist"
  if ! monitor_frontend_needs_build; then
    return 0
  fi

  if ! command -v bun >/dev/null 2>&1; then
    echo "error: monitor frontend build output not found at $dist_dir" >&2
    echo "install bun and build frontend assets:" >&2
    echo "  (cd \"$PROJECT_ROOT/web/monitor\" && bun install --frozen-lockfile && bun run build)" >&2
    exit 1
  fi

  (
    cd "$PROJECT_ROOT/web/monitor"
    bun install --frozen-lockfile
    bun run build
  )
}

first_non_flag_arg() {
  local skip_next=0
  for arg in "$@"; do
    if [[ "$skip_next" == "1" ]]; then
      skip_next=0
      continue
    fi
    case "$arg" in
      --config|--output)
        skip_next=1
        ;;
      --config=*|--output=*|--verbose|--help|-h|--version)
        ;;
      -*)
        ;;
      *)
        printf '%s\n' "$arg"
        return 0
        ;;
    esac
  done
  return 1
}

run_service_arg() {
  local saw_run=0
  local skip_next=0
  for arg in "$@"; do
    if [[ "$skip_next" == "1" ]]; then
      skip_next=0
      continue
    fi
    case "$arg" in
      --config|--output)
        skip_next=1
        continue
        ;;
      --config=*|--output=*|--verbose|--help|-h|--version)
        continue
        ;;
      -*)
        continue
        ;;
    esac

    if [[ "$saw_run" == "1" ]]; then
      printf '%s\n' "$arg"
      return 0
    fi

    if [[ "$arg" == "run" ]]; then
      saw_run=1
    fi
  done
  return 1
}

if [[ "${MORAINE_CTL_USE_CARGO_RUN:-0}" == "1" ]]; then
  exec "$CARGO_BIN" run --manifest-path "$CRATE_MANIFEST" -- "$@"
fi

if [[ "${MORAINE_CTL_SKIP_BUILD:-0}" != "1" ]]; then
  "$CARGO_BIN" build --manifest-path "$CRATE_MANIFEST"
elif [[ ! -x "$BIN_PATH" ]]; then
  echo "error: $BIN_PATH not found and build is disabled (set MORAINE_CTL_SKIP_BUILD=0)." >&2
  exit 1
fi

# Running through the source-tree wrapper should "just work" for sibling binaries.
: "${MORAINE_SOURCE_TREE_MODE:=1}"
export MORAINE_SOURCE_TREE_MODE

command_name="$(first_non_flag_arg "$@" || true)"
if [[ "$command_name" == "up" ]]; then
  if monitor_enabled_for_up "$@"; then
    ensure_monitor_frontend
  fi
fi

if [[ "$command_name" == "run" ]]; then
  service_name="$(run_service_arg "$@" || true)"
  case "$service_name" in
    ingest)
      build_binary "$PROJECT_ROOT/apps/moraine-ingest/Cargo.toml"
      ;;
    monitor)
      if ! has_flag "--static-dir" "$@"; then
        ensure_monitor_frontend
      fi
      build_binary "$PROJECT_ROOT/apps/moraine-monitor/Cargo.toml"
      ;;
    mcp)
      build_binary "$PROJECT_ROOT/apps/moraine-mcp/Cargo.toml"
      ;;
  esac
fi

exec "$BIN_PATH" "$@"
