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

: <<'DOC'
Initializes a consumer repository for shellops.

Ensures the project has:
  - An ops dispatcher at $PROJ/shell/ops
  - An action dispatcher at $PROJ/shell/action
  - An .envrc that exports PROJ and sources shellops's .envrc
  - A .gitignore entry for the copied dispatchers (shell/ops, shell/action)

If an ops.lock file exists, automatically runs `ops install`
to install declared tools.

Idempotent: safe to re-run on an already-initialized repo.

Usage: shell/.ops/init [-h,--help] [--no-install] [--install tool...]

Flags:
  --no-install          Skip all tool installation from ops.lock.
  --install tool...     Install only the specified tools from ops.lock.
  -h, --help            Show this help text.
DOC

# compute SHELLOPS_DIR and PROJ from this script's location.
SHELLOPS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export SHELLOPS_DIR

PROJ="$(cd "$SHELLOPS_DIR" && git rev-parse --show-superproject-working-tree 2>/dev/null)"

if [[ -z "$PROJ" ]]; then
  PROJ="$(cd "$SHELLOPS_DIR" && git rev-parse --show-toplevel)"
fi

export PROJ

source "$SHELLOPS_DIR/.envrc"

if ! command -v jq >/dev/null 2>&1; then
  log "jq not found, bootstrapping..."
  source "$SHELLOPS_DIR/lib/system_packages.api.sh"
  system_packages_install jq
fi

USAGE="$(cat <<'EOF'
Initializes a consumer repository for shellops.

Usage: shell/.ops/init [-h,--help] [-n, --no-install] [--install tool...]

Sets up:
  - shell/ops dispatcher
  - shell/action dispatcher
  - .envrc (creates or patches)
  - .gitignore entries for shell/ops and shell/action
  - Runs tool installation if ops.lock exists (unless --no-install)

Flags:
  --no-install          Skip all tool installation.
  --install tool...     Install only the specified tools (implies --no-install
                        for everything else).
EOF
)"

# shellcheck disable=SC2016
ENVRC_SOURCE='source "$PROJ/shell/.ops/.envrc"'

ENVRC_TEMPLATE="$(cat <<'TMPL'
#!/usr/bin/env bash

export PROJ="$(git rev-parse --show-toplevel)"

source "$PROJ/shell/.ops/.envrc"
TMPL
)"

GITIGNORE_ENTRIES=("shell/ops" "shell/action")
GITIGNORE_COMMENT="# Derived from shellops submodule"

FLAG_NO_INSTALL=false
FLAG_INSTALL_TOOLS=()

function main() {
  parse_args "$@"

  log "Initializing shellops in $PROJ..."

  install_dispatcher "ops"
  install_dispatcher "action"
  ensure_envrc
  ensure_gitignore
  persist_env

  if [[ "$FLAG_NO_INSTALL" = true ]]; then
    log "Done (skipped tool installation)."
    return
  fi

  if [[ ! -f "$PROJ/ops.lock" && ! -f "$SHELLOPS_DIR/ops.lock" ]]; then
    log "Done."
    return
  fi

  if [[ ${#FLAG_INSTALL_TOOLS[@]} -gt 0 ]]; then
    log "Installing tools: ${FLAG_INSTALL_TOOLS[*]}..."
    "$SHELLOPS_DIR/cli/install" "${FLAG_INSTALL_TOOLS[@]}"
  else
    log "Installing tools..."
    "$SHELLOPS_DIR/cli/install"
  fi

  log "Done."
}

function install_dispatcher() {
  local name="$1"
  local target="$PROJ/shell/$name"
  mkdir -p "$(dirname "$target")"
  cp "$SHELLOPS_DIR/$name" "$target"
  chmod +x "$target"
  log "  Installed dispatcher at shell/$name"
}

function ensure_envrc() {
  local envrc="$PROJ/.envrc"

  if [[ ! -f "$envrc" ]]; then
    create_envrc "$envrc"
    return
  fi

  patch_envrc "$envrc"
}

function create_envrc() {
  local envrc="$1"
  printf '%s\n' "$ENVRC_TEMPLATE" > "$envrc"
  log "  Created .envrc"
}

function patch_envrc() {
  local envrc="$1"

  if grep -qF "$ENVRC_SOURCE" "$envrc"; then
    log "  .envrc already sources shellops"
    return
  fi

  printf '\n%s\n' "$ENVRC_SOURCE" >> "$envrc"
  log "  Patched .envrc with shellops source"
}

function ensure_gitignore() {
  local gitignore="$PROJ/.gitignore"

  for entry in "${GITIGNORE_ENTRIES[@]}"; do
    ensure_gitignore_entry "$gitignore" "$entry"
  done
}

function ensure_gitignore_entry() {
  local gitignore="$1" entry="$2"

  if [[ ! -f "$gitignore" ]]; then
    printf '%s\n%s\n' "$GITIGNORE_COMMENT" "$entry" > "$gitignore"
    log "  Created .gitignore with $entry"
    return
  fi

  if grep -qxF "$entry" "$gitignore"; then
    log "  .gitignore already has $entry"
    return
  fi

  printf '\n%s\n%s\n' "$GITIGNORE_COMMENT" "$entry" >> "$gitignore"
  log "  Added $entry to .gitignore"
}

function persist_env() {
  if [[ -z "${GITHUB_ENV:-}" ]]; then
    return
  fi

  echo "PROJ=$PROJ" >> "$GITHUB_ENV"
  echo "SHELLOPS_DIR=$SHELLOPS_DIR" >> "$GITHUB_ENV"
  log "  Exported PROJ and SHELLOPS_DIR to GITHUB_ENV"
}

function parse_args() {
  while [[ $# -gt 0 ]]; do
    case "$1" in
      -n|--no-install) FLAG_NO_INSTALL=true ;;
      --install)
        shift
        while [[ $# -gt 0 && "$1" != -* ]]; do
          FLAG_INSTALL_TOOLS+=("$1")
          shift
        done
        continue
        ;;
      -h|--help) log "$USAGE" && exit 0 ;;
      -*)
        log "Unknown option: $1"
        log "$USAGE"
        exit 1
        ;;
    esac
    shift
  done
}

main "$@"
