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

MOSAIC_HOME="${MOSAIC_HOME:-$HOME/.config/mosaic}"
PROJECTS_FILE="$MOSAIC_HOME/projects.txt"

usage() {
  cat <<USAGE
Usage: $(basename "$0") <command> [options]

Commands:
  init
      Create projects registry file at ~/.config/mosaic/projects.txt

  add <repo-path> [repo-path...]
      Add one or more repos to the registry

  remove <repo-path> [repo-path...]
      Remove one or more repos from the registry

  list
      Show registered repos

  bootstrap [--all|repo-path...] [--force] [--quality-template <name>]
      Bootstrap registered repos or explicit repo paths

  orchestrate <drain|start|status|stop> [--all|repo-path...] [--poll-sec N] [--no-sync] [--worker-cmd "cmd"]
      Run orchestrator actions across repos from one command

Examples:
  mosaic-projects init
  mosaic-projects add ~/src/syncagent ~/src/inventory-stickers
  mosaic-projects bootstrap --all
  mosaic-projects orchestrate drain --all --worker-cmd "codex -p"
  mosaic-projects orchestrate start ~/src/syncagent --worker-cmd "opencode -p"
USAGE
}

ensure_registry() {
  mkdir -p "$MOSAIC_HOME"
  if [[ ! -f "$PROJECTS_FILE" ]]; then
    cat > "$PROJECTS_FILE" <<EOF
# Mosaic managed projects (one absolute path per line)
# Lines starting with # are ignored.
EOF
  fi
}

norm_path() {
  local p="$1"
  if [[ -d "$p" ]]; then
    (cd "$p" && pwd)
  else
    return 1
  fi
}

read_registry() {
  ensure_registry
  grep -vE '^\s*#|^\s*$' "$PROJECTS_FILE" | while read -r p; do
    [[ -d "$p" ]] && echo "$p"
  done
}

add_repo() {
  local p="$1"
  ensure_registry
  local np
  np="$(norm_path "$p")" || { echo "[mosaic-projects] skip missing dir: $p" >&2; return 1; }
  if grep -Fxq "$np" "$PROJECTS_FILE"; then
    echo "[mosaic-projects] already registered: $np"
    return 0
  fi
  echo "$np" >> "$PROJECTS_FILE"
  echo "[mosaic-projects] added: $np"
}

remove_repo() {
  local p="$1"
  ensure_registry
  local np
  np="$(norm_path "$p" 2>/dev/null || echo "$p")"
  tmp="$(mktemp)"
  grep -vFx "$np" "$PROJECTS_FILE" > "$tmp" || true
  mv "$tmp" "$PROJECTS_FILE"
  echo "[mosaic-projects] removed: $np"
}

resolve_targets() {
  local use_all="$1"
  shift
  if [[ "$use_all" == "1" ]]; then
    read_registry
    return 0
  fi
  if [[ $# -gt 0 ]]; then
    for p in "$@"; do
      norm_path "$p" || { echo "[mosaic-projects] missing target: $p" >&2; exit 1; }
    done
    return 0
  fi
  if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
    git rev-parse --show-toplevel
    return 0
  fi
  echo "[mosaic-projects] no targets provided. Use --all or pass repo paths." >&2
  exit 1
}

cmd="${1:-}"
if [[ -z "$cmd" ]]; then
  usage
  exit 1
fi
shift || true

case "$cmd" in
  init)
    ensure_registry
    echo "[mosaic-projects] registry ready: $PROJECTS_FILE"
    ;;
  add)
    [[ $# -gt 0 ]] || { echo "[mosaic-projects] add requires repo path(s)" >&2; exit 1; }
    for p in "$@"; do add_repo "$p"; done
    ;;
  remove)
    [[ $# -gt 0 ]] || { echo "[mosaic-projects] remove requires repo path(s)" >&2; exit 1; }
    for p in "$@"; do remove_repo "$p"; done
    ;;
  list)
    read_registry
    ;;
  bootstrap)
    use_all=0
    force=0
    quality_template=""
    targets=()
    while [[ $# -gt 0 ]]; do
      case "$1" in
        --all) use_all=1; shift ;;
        --force) force=1; shift ;;
        --quality-template) quality_template="${2:-}"; shift 2 ;;
        *) targets+=("$1"); shift ;;
      esac
    done
    mapfile -t repos < <(resolve_targets "$use_all" "${targets[@]}")
    [[ ${#repos[@]} -gt 0 ]] || { echo "[mosaic-projects] no repos resolved"; exit 1; }
    for repo in "${repos[@]}"; do
      args=()
      [[ $force -eq 1 ]] && args+=(--force)
      [[ -n "$quality_template" ]] && args+=(--quality-template "$quality_template")
      args+=("$repo")
      echo "[mosaic-projects] bootstrap: $repo"
      "$MOSAIC_HOME/tools/_scripts/mosaic-bootstrap-repo" "${args[@]}"
      add_repo "$repo" || true
    done
    ;;
  orchestrate)
    action="${1:-}"
    [[ -n "$action" ]] || { echo "[mosaic-projects] orchestrate requires action: drain|start|status|stop" >&2; exit 1; }
    shift || true
    use_all=0
    poll_sec=15
    no_sync=0
    worker_cmd=""
    targets=()
    while [[ $# -gt 0 ]]; do
      case "$1" in
        --all) use_all=1; shift ;;
        --poll-sec) poll_sec="${2:-15}"; shift 2 ;;
        --no-sync) no_sync=1; shift ;;
        --worker-cmd) worker_cmd="${2:-}"; shift 2 ;;
        *) targets+=("$1"); shift ;;
      esac
    done
    mapfile -t repos < <(resolve_targets "$use_all" "${targets[@]}")
    [[ ${#repos[@]} -gt 0 ]] || { echo "[mosaic-projects] no repos resolved"; exit 1; }

    for repo in "${repos[@]}"; do
      echo "[mosaic-projects] orchestrate:$action -> $repo"
      (
        cd "$repo"
        if [[ -n "$worker_cmd" ]]; then
          export MOSAIC_WORKER_EXEC="$worker_cmd"
        fi
        if [[ -x "scripts/agent/orchestrator-daemon.sh" ]]; then
          args=()
          [[ "$action" == "start" || "$action" == "drain" ]] && args+=(--poll-sec "$poll_sec")
          [[ $no_sync -eq 1 ]] && args+=(--no-sync)
          bash scripts/agent/orchestrator-daemon.sh "$action" "${args[@]}"
        else
          case "$action" in
            drain)
              args=(--poll-sec "$poll_sec")
              [[ $no_sync -eq 1 ]] && args+=(--no-sync)
              "$MOSAIC_HOME/tools/_scripts/mosaic-orchestrator-drain" "${args[@]}"
              ;;
            status)
              echo "[mosaic-projects] no daemon script in repo; run from bootstrapped repo or re-bootstrap"
              ;;
            start|stop)
              echo "[mosaic-projects] action '$action' requires scripts/agent/orchestrator-daemon.sh (run bootstrap first)" >&2
              exit 1
              ;;
            *)
              echo "[mosaic-projects] unsupported action: $action" >&2
              exit 1
              ;;
          esac
        fi
      )
    done
    ;;
  *)
    usage
    exit 1
    ;;
esac
