# shellcheck shell=bash
# lib-dev-hub-mdbook.sh — install mdBook (Rust static-site doc-hub) via cargo + launchd.
#
# Renders every ~/Projects/<repo>/{CLAUDE,DECISIONS,RUNBOOK,DESIGN}.md as a
# single browsable web book served on http://127.0.0.1:7080/. Two launchd
# agents: `mdbook-server` (long-lived, --no-rebuild) and `mdbook-rebuilder`
# (timer, regenerates SUMMARY.md + chapters + `mdbook build` every 3600s).
#
# The rebuild logic is owned by ${KIT}/dev-hub/mdbook-rebuild.sh — emitted by
# write_rebuild_wrapper. regenerate_summary is a thin wrapper that invokes it
# synchronously at install time so the user sees the first render immediately.
#
# Sources: lib-log.sh (say/warn/err), lib-launchd.sh (install_service/unload_plist).
# Globals read: $KIT_DIR, $HOME_DIR.

# ---------- helpers (private) ----------

# Verify cargo is on PATH (rustup default stable). 0 OK, 1 missing.
_mdbook_check_cargo() {
  if ! command -v cargo >/dev/null 2>&1; then
    err "cargo not found — install via: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh"
    return 1
  fi
  say "  → cargo $(cargo --version 2>/dev/null) OK"
}

# Idempotent `cargo install mdbook`. Cargo no-ops if already at latest crate.
_mdbook_install_binary() {
  say "  → cargo install mdbook (no-op if already at latest)"
  cargo install mdbook 2>&1 | grep -vE "^(\s*Compiling|\s*Finished|\s*Updating)" || true
}

# Render install/launchd-templates/book.toml.tmpl → ${DATA}/book.toml.
# Args: <data-dir>.
_mdbook_render_book_toml() {
  local data_dir="$1"
  local tmpl="$KIT_DIR/install/launchd-templates/book.toml.tmpl"
  if [ ! -f "$tmpl" ]; then
    err "book.toml.tmpl missing: $tmpl"
    return 1
  fi
  mkdir -p "$data_dir"
  sed \
    -e "s|\${HOME}|${HOME_DIR}|g" \
    -e "s|\${USER}|${USER}|g" \
    -e "s|\${DATA}|${data_dir}|g" \
    "$tmpl" > "$data_dir/book.toml"
  say "  → wrote $data_dir/book.toml"
}

# Emit ${KIT}/dev-hub/mdbook-serve.sh — wraps `mdbook serve` with binary discovery.
write_serve_wrapper() {
  local wrapper="$HOME_DIR/.claude/agents/_primitives/dev-hub/mdbook-serve.sh"
  mkdir -p "$(dirname "$wrapper")"
  cat > "$wrapper" <<'WRAPPER_EOF'
#!/usr/bin/env bash
# Auto-generated by lib-dev-hub-mdbook.sh — do not edit by hand.
# Resolves mdbook binary (cargo / brew / PATH) and serves the rendered book.
set -eu
DATA="$HOME/Library/Application Support/keisei/mdbook"
MDBOOK="$(command -v mdbook || echo "$HOME/.cargo/bin/mdbook")"
[ -x "$MDBOOK" ] || { echo "mdbook not found (tried PATH and ~/.cargo/bin/mdbook)" >&2; exit 1; }
exec "$MDBOOK" serve "$DATA" \
  --hostname 127.0.0.1 --port 7080 --no-rebuild
WRAPPER_EOF
  chmod +x "$wrapper"
  say "  → wrote $wrapper"
}

# Emit ${KIT}/dev-hub/mdbook-rebuild.sh — regenerates src/ tree + `mdbook build`.
# Idempotent: every run wipes & rebuilds src/ from ~/Projects/.
write_rebuild_wrapper() {
  local wrapper="$HOME_DIR/.claude/agents/_primitives/dev-hub/mdbook-rebuild.sh"
  mkdir -p "$(dirname "$wrapper")"
  cat > "$wrapper" <<'WRAPPER_EOF'
#!/usr/bin/env bash
# Auto-generated by lib-dev-hub-mdbook.sh — do not edit by hand.
# Regenerate SUMMARY.md + chapters from ~/Projects/ + rebuild book.
set -e
DATA="$HOME/Library/Application Support/keisei/mdbook"
LOGS="$HOME/Library/Logs/keisei/mdbook"
mkdir -p "$DATA/src" "$LOGS"

# Helper: slugify project name (lowercase, non-alphanum → '-', collapse, trim).
slugify() {
    echo "$1" | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9' '-' | sed 's/--*/-/g; s/^-//; s/-$//'
}

# Find mdbook binary (cargo or brew).
MDBOOK="$(command -v mdbook || echo "$HOME/.cargo/bin/mdbook")"
[ -x "$MDBOOK" ] || { echo "mdbook not found" >&2; exit 1; }

# Wipe + regen src tree (chapter content only — book.toml stays at $DATA/book.toml).
rm -rf "$DATA/src"
mkdir -p "$DATA/src"

SUMMARY="$DATA/src/SUMMARY.md"
echo "# Summary" > "$SUMMARY"
echo "" >> "$SUMMARY"

for proj in "$HOME/Projects"/*/; do
    [ -d "$proj.git" ] || continue
    name="$(basename "$proj")"
    slug="$(slugify "$name")"
    chapter_dir="$DATA/src/$slug"
    mkdir -p "$chapter_dir"

    if [ -f "$proj/CLAUDE.md" ]; then
        cp "$proj/CLAUDE.md" "$chapter_dir/index.md"
    elif [ -f "$proj/README.md" ]; then
        cp "$proj/README.md" "$chapter_dir/index.md"
    else
        # No CLAUDE.md and no README.md → skip empty chapter.
        rmdir "$chapter_dir" 2>/dev/null || true
        continue
    fi

    echo "- [$name](./$slug/index.md)" >> "$SUMMARY"

    for doc in DECISIONS.md RUNBOOK.md DESIGN.md; do
        if [ -f "$proj/$doc" ]; then
            lower="$(echo "${doc%.md}" | tr '[:upper:]' '[:lower:]')"
            cp "$proj/$doc" "$chapter_dir/${lower}.md" 2>/dev/null || true
            echo "  - [${doc%.md}](./$slug/${lower}.md)" >> "$SUMMARY"
        fi
    done
done

"$MDBOOK" build "$DATA" 2>>"$LOGS/rebuilder.err.log"
echo "rebuilt at $(date -u +%FT%TZ)"
WRAPPER_EOF
  chmod +x "$wrapper"
  say "  → wrote $wrapper"
}

# ---------- public API ----------

# Walk ~/Projects/ and (re)generate ${DATA}/src/* + SUMMARY.md.
# Delegates to mdbook-rebuild.sh so install-time and timer use identical logic.
regenerate_summary() {
  local rebuild="$HOME_DIR/.claude/agents/_primitives/dev-hub/mdbook-rebuild.sh"
  if [ ! -x "$rebuild" ]; then
    err "mdbook-rebuild.sh not found — call write_rebuild_wrapper first"
    return 1
  fi
  say "  → regenerating chapter tree from $HOME_DIR/Projects/"
  "$rebuild" >/dev/null
}

# Install mdBook + render config + first build + register both launchd agents.
# Idempotent.
install_dev_hub_mdbook() {
  say "installing dev-hub-mdbook"
  _mdbook_check_cargo || return 1
  _mdbook_install_binary

  local data_dir="$HOME_DIR/Library/Application Support/keisei/mdbook"
  mkdir -p "$data_dir/src" "$data_dir/book"
  _mdbook_render_book_toml "$data_dir" || return 1

  write_serve_wrapper
  write_rebuild_wrapper
  regenerate_summary || return 1

  # shellcheck source=./lib-launchd.sh
  . "$KIT_DIR/install/lib-launchd.sh"
  install_service mdbook-server
  install_service mdbook-rebuilder

  say "mdBook served on http://127.0.0.1:7080/. Rebuilds every 1h."
}

# Unload + remove both plists. Optional --purge also `cargo uninstall mdbook`.
uninstall_dev_hub_mdbook() {
  say "uninstalling dev-hub-mdbook"
  # shellcheck source=./lib-launchd.sh
  . "$KIT_DIR/install/lib-launchd.sh"
  unload_plist mdbook-server
  unload_plist mdbook-rebuilder
  rm -f "$HOME_DIR/.claude/agents/_primitives/dev-hub/mdbook-serve.sh"
  rm -f "$HOME_DIR/.claude/agents/_primitives/dev-hub/mdbook-rebuild.sh"
  if [ "${1:-}" = "--purge" ] && command -v cargo >/dev/null 2>&1; then
    say "  → cargo uninstall mdbook"
    cargo uninstall mdbook || true
  fi
}

# Verify mdBook server returns 200 on http://127.0.0.1:7080/. 0 OK, 1 fail.
verify_dev_hub_mdbook() {
  local code
  code="$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:7080/ 2>/dev/null || echo 000)"
  if [ "$code" = "200" ]; then
    say "mdbook server health OK (200)"
    return 0
  fi
  err "mdbook server health failed (HTTP $code) — check logs at $HOME_DIR/Library/Logs/keisei/mdbook-server/"
  return 1
}
