#!/usr/bin/env bash
# deckctl bootstrap — doctor-gated, ordered, idempotent per-module provisioning.
set -euo pipefail

BOOTSTRAP_STATE_BASE=""
BOOTSTRAP_STATUS=""
BOOTSTRAP_ROWS=()
BOOTSTRAP_STEPS=(bootstrap sync install units health)

bootstrap_usage() {
  echo "usage: deckctl bootstrap [--module <name>]" >&2
  exit 2
}

bootstrap_install_mode() { # $1=manifest
  jq -r '.install.mode // ""' "$1"
}

bootstrap_artifact_root() { # $1=module
  printf '%s\n' "${HOME:?}/.local/opt/overdeck/$1/current"
}

bootstrap_do_bootstrap() { # $1=module $2=moddir $3=manifest
  local mod="$1" moddir="$2" manifest="$3" rel stamp digest
  BOOTSTRAP_STATUS="n/a"

  jq -e 'has("bootstrap")' "$manifest" >/dev/null 2>&1 || return 0
  rel=$(jq -r '.bootstrap' "$manifest")
  if [[ ! -x "$moddir/${rel#./}" ]]; then
    echo "bootstrap: $mod: bootstrap script not executable: $rel" >&2
    return 1
  fi

  digest=$(sha256sum "$moddir/${rel#./}" | cut -d' ' -f1)
  stamp="$BOOTSTRAP_STATE_BASE/$mod/bootstrap.sha256"
  if [[ -f "$stamp" && "$(<"$stamp")" == "$digest" ]]; then
    BOOTSTRAP_STATUS="cached"
    return 0
  fi

  if ! (cd "$moddir" && "./${rel#./}"); then
    echo "bootstrap: $mod: bootstrap script failed: $rel" >&2
    return 1
  fi

  mkdir -p "$(dirname "$stamp")"
  printf '%s\n' "$digest" >"$stamp"
  BOOTSTRAP_STATUS="ok"
}

bootstrap_do_sync() { # $1=module
  local mod="$1"
  BOOTSTRAP_STATUS="n/a"
  [[ "$mod" == "workstation" ]] || return 0

  if "$DECKCTL_ROOT/bin/deckctl" sync diff >/dev/null 2>&1; then
    BOOTSTRAP_STATUS="cached"
    return 0
  fi
  if ! "$DECKCTL_ROOT/bin/deckctl" sync apply; then
    echo "bootstrap: $mod: sync apply failed" >&2
    return 1
  fi
  BOOTSTRAP_STATUS="ok"
}

bootstrap_do_install() { # $1=module $2=moddir $3=manifest
  local mod="$1" manifest="$3" out
  BOOTSTRAP_STATUS="n/a"
  [[ "$(bootstrap_install_mode "$manifest")" == "artifact" ]] || return 0

  if ! out=$("$DECKCTL_ROOT/bin/deckctl" install "$mod" 2>&1); then
    printf '%s\n' "$out" >&2
    echo "bootstrap: $mod: install failed" >&2
    return 1
  fi
  printf '%s\n' "$out"

  if printf '%s\n' "$out" | grep -q 'already current'; then
    BOOTSTRAP_STATUS="cached"
  else
    BOOTSTRAP_STATUS="ok"
  fi
}

bootstrap_do_units() { # $1=module $2=moddir $3=manifest
  local mod="$1" moddir="$2" manifest="$3"
  local unit_dir="${HOME:?}/.config/systemd/user"
  local src_base="$moddir" svc unit link target changed=0 enabled=0
  BOOTSTRAP_STATUS="n/a"

  jq -e '.services | type == "array" and length > 0' "$manifest" >/dev/null 2>&1 || return 0

  if ! command -v systemctl >/dev/null 2>&1; then
    echo "bootstrap: $mod: systemctl not found (module declares services)" >&2
    return 1
  fi

  if [[ "$(bootstrap_install_mode "$manifest")" == "artifact" ]]; then
    src_base=$(bootstrap_artifact_root "$mod")
    if [[ ! -d "$src_base" ]]; then
      echo "bootstrap: $mod: installed artifact missing at $src_base" >&2
      return 1
    fi
  fi

  mkdir -p "$unit_dir"
  while IFS= read -r svc; do
    [[ -n "$svc" ]] || continue
    target="$src_base/$svc"
    if [[ ! -f "$target" ]]; then
      echo "bootstrap: $mod: unit file missing: $target" >&2
      return 1
    fi
    unit=$(basename "$svc")
    link="$unit_dir/$unit"
    if [[ ! -L "$link" || "$(readlink "$link")" != "$target" ]]; then
      ln -sfn "$target" "$link"
      changed=1
    fi
  done < <(jq -r '.services[]?' "$manifest")

  if [[ "$changed" -eq 1 ]] && ! systemctl --user daemon-reload; then
    echo "bootstrap: $mod: systemctl daemon-reload failed" >&2
    return 1
  fi

  while IFS= read -r svc; do
    [[ -n "$svc" ]] || continue
    unit=$(basename "$svc")
    systemctl --user is-enabled "$unit" >/dev/null 2>&1 && continue
    if ! systemctl --user enable "$unit"; then
      echo "bootstrap: $mod: failed to enable $unit" >&2
      return 1
    fi
    enabled=1
  done < <(jq -r '.services[]?' "$manifest")

  if [[ "$changed" -eq 0 && "$enabled" -eq 0 ]]; then
    BOOTSTRAP_STATUS="cached"
  else
    BOOTSTRAP_STATUS="ok"
  fi
}

bootstrap_do_health() { # $1=module $2=moddir $3=manifest
  local mod="$1" moddir="$2" manifest="$3" rel run_dir rc=0
  BOOTSTRAP_STATUS="n/a"

  jq -e 'has("health")' "$manifest" >/dev/null 2>&1 || return 0
  rel=$(jq -r '.health' "$manifest")

  run_dir="$moddir"
  if [[ "$(bootstrap_install_mode "$manifest")" == "artifact" ]]; then
    run_dir=$(bootstrap_artifact_root "$mod")
    export DECKCTL_ARTIFACT_ROOT="$run_dir"
  fi

  if [[ ! -x "$run_dir/${rel#./}" ]]; then
    unset DECKCTL_ARTIFACT_ROOT
    echo "bootstrap: $mod: health script not executable: $run_dir/${rel#./}" >&2
    return 1
  fi

  (cd "$run_dir" && "./${rel#./}") || rc=1
  unset DECKCTL_ARTIFACT_ROOT

  if [[ "$rc" -ne 0 ]]; then
    echo "bootstrap: $mod: health check failed" >&2
    return 1
  fi
  BOOTSTRAP_STATUS="ok"
}

bootstrap_run_module() { # $1=module
  local mod="$1" step rc=0
  local moddir="$DECKCTL_ROOT/modules/$mod"
  local manifest="$moddir/deck.module.json"
  local -a cells=()

  [[ -f "$manifest" ]] || die "bootstrap: module '$mod' has no deck.module.json"

  echo "bootstrap: $mod"
  for step in "${BOOTSTRAP_STEPS[@]}"; do
    if "bootstrap_do_$step" "$mod" "$moddir" "$manifest"; then
      cells+=("$BOOTSTRAP_STATUS")
    else
      cells+=("FAIL")
      rc=1
      break
    fi
  done

  while [[ ${#cells[@]} -lt ${#BOOTSTRAP_STEPS[@]} ]]; do
    cells+=("-")
  done

  local joined
  printf -v joined '%s\t' "$mod" "${cells[@]}"
  BOOTSTRAP_ROWS+=("${joined%$'\t'}")
  return "$rc"
}

bootstrap_print_summary() {
  local row mod a b c d e
  printf "%-16s %-10s %-10s %-10s %-10s %s\n" "MODULE" "BOOTSTRAP" "SYNC" "INSTALL" "UNITS" "HEALTH"
  for row in ${BOOTSTRAP_ROWS[@]+"${BOOTSTRAP_ROWS[@]}"}; do
    IFS=$'\t' read -r mod a b c d e <<<"$row"
    printf "%-16s %-10s %-10s %-10s %-10s %s\n" "$mod" "$a" "$b" "$c" "$d" "$e"
  done
}

cmd_bootstrap() {
  local only="" module manifest found=0
  local -a modules=()

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --module)
        [[ $# -ge 2 ]] || die "bootstrap: --module requires a module name"
        only="$2"
        shift 2
        ;;
      --module=*)
        only="${1#--module=}"
        [[ -n "$only" ]] || die "bootstrap: --module requires a module name"
        shift
        ;;
      *) bootstrap_usage ;;
    esac
  done

  [[ -d "$DECKCTL_ROOT/modules" ]] || die "missing modules/ directory at $DECKCTL_ROOT"
  BOOTSTRAP_STATE_BASE="${HOME:?}/.local/state/overdeck/bootstrap"

  while IFS= read -r manifest; do
    [[ -n "$manifest" ]] || continue
    modules+=("$(basename "$(dirname "$manifest")")")
  done < <(find "$DECKCTL_ROOT/modules" -mindepth 2 -maxdepth 2 -name 'deck.module.json' | sort)

  [[ ${#modules[@]} -gt 0 ]] || die "bootstrap: no modules found under $DECKCTL_ROOT/modules"

  if [[ -n "$only" ]]; then
    for module in "${modules[@]}"; do
      [[ "$module" == "$only" ]] && found=1
    done
    [[ "$found" -eq 1 ]] || die "bootstrap: unknown module '$only'"
    modules=("$only")
  fi

  echo "bootstrap: doctor"
  if ! "$DECKCTL_ROOT/bin/deckctl" doctor; then
    echo "bootstrap: doctor failed — refusing to provision" >&2
    exit 1
  fi

  echo "bootstrap: units"
  if ! "$DECKCTL_ROOT/bin/deckctl" units apply; then
    echo "bootstrap: units apply failed" >&2
    exit 1
  fi

  local failed=""
  for module in "${modules[@]}"; do
    if ! bootstrap_run_module "$module"; then
      failed="$module"
      break
    fi
  done

  bootstrap_print_summary

  if [[ -n "$failed" ]]; then
    echo "bootstrap: stopped at module '$failed' — fix and re-run to continue" >&2
    exit 1
  fi
}
