#!/usr/bin/env bash
# import-module.sh <source-path> <module-name> — history-preserving import of a
# source repo into modules/<module-name>/ on feat/ai-os-foundation.
# Fail-closed: operates on a scratch clone only; gitleaks over filtered history
# blocks the merge; live checkouts are never touched.
set -euo pipefail

die() { echo "import-module: ERROR: $*" >&2; exit 1; }

[[ $# -eq 2 ]] || die "usage: import-module.sh <source-path> <module-name>"
SRC=$(realpath "$1")
NAME="$2"
BRANCH="${IMPORT_BRANCH:-feat/ai-os-foundation}"
BUNDLE_DIR="${IMPORT_BUNDLE_DIR:-$HOME/.local/state/overdeck/bundles}"
BUNDLE="$BUNDLE_DIR/$NAME-pre-ai-os.bundle"

command -v git-filter-repo >/dev/null || die "git-filter-repo not installed"
command -v gitleaks >/dev/null || die "gitleaks not installed"

# Junk strip list per module: tracked paths only (untracked never clones).
strip_args=()
case "$NAME" in
  harness)  strip=(tmp runstate scratchpad node_modules mega-plan-harness web "tui/target" .worktrees) ;;
  systray)  strip=(__pycache__ tmp runstate) ;;
  security) strip=(__pycache__ scratchpad tmp apps/web) ;;
  monitor)  strip=(tmp __pycache__) ;;
  *) die "unknown module '$NAME' (no strip list defined)" ;;
esac
for p in "${strip[@]}"; do strip_args+=(--path "$p"); done

# Preconditions — all fail-closed.
[[ -d "$SRC/.git" ]] || die "$SRC is not a git repo"
[[ -n "$(git -C "$SRC" status --porcelain)" ]] && die "$SRC has uncommitted changes — park WIP first"
[[ -f "$BUNDLE" ]] || die "missing pre-migration bundle $BUNDLE — create it first"
repo_root=$(git rev-parse --show-toplevel)
[[ "$(basename "$repo_root")" == "overdeck" || -f "$repo_root/spec/deck-module.schema.json" || -d "$repo_root/docs/specs" ]] || die "run from the overdeck checkout"
cur_branch=$(git branch --show-current)
[[ "$cur_branch" == "$BRANCH" ]] || die "overdeck must be on $BRANCH (on '$cur_branch')"
[[ -e "$repo_root/modules/$NAME" ]] && die "modules/$NAME already exists"

src_sha=$(git -C "$SRC" rev-parse HEAD)
src_branch=$(git -C "$SRC" branch --show-current)
[[ -n "$src_branch" ]] || die "$SRC is on a detached HEAD — create/park a branch first"

SCRATCH=$(mktemp -d "${TMPDIR:-/tmp}/import-$NAME-XXXXXX")
trap 'rm -rf "$SCRATCH"' EXIT

echo "import-module: cloning $SRC (branch $src_branch) -> scratch"
git clone --no-local --single-branch --branch "$src_branch" "$SRC" "$SCRATCH/clone" >/dev/null 2>&1

echo "import-module: filter-repo: strip ${strip[*]} ; prefix modules/$NAME/"
git -C "$SCRATCH/clone" filter-repo --invert-paths "${strip_args[@]}" --force >/dev/null
git -C "$SCRATCH/clone" filter-repo --to-subdirectory-filter "modules/$NAME" --force >/dev/null

echo "import-module: gitleaks over full filtered history"
ignore_args=()
[[ -f "$repo_root/.gitleaksignore" ]] && ignore_args=(--gitleaks-ignore-path "$repo_root/.gitleaksignore")
if ! gitleaks git --no-banner --exit-code 9 "${ignore_args[@]}" --report-path "$SCRATCH/gitleaks-$NAME.json" "$SCRATCH/clone" >/dev/null 2>&1; then
  cp "$SCRATCH/gitleaks-$NAME.json" "$repo_root/tmp/gitleaks-$NAME.json" 2>/dev/null || cp "$SCRATCH/gitleaks-$NAME.json" "/tmp/gitleaks-$NAME.json"
  die "gitleaks found secrets in $NAME filtered history — report at tmp/gitleaks-$NAME.json; scrub before import"
fi

filtered_head=$(git -C "$SCRATCH/clone" rev-parse HEAD)
echo "import-module: merging into $BRANCH"
git fetch "$SCRATCH/clone" HEAD
git merge --allow-unrelated-histories --no-ff -m "import: $NAME ($SRC @ ${src_sha:0:12})" "$filtered_head" >/dev/null

echo "import-module: OK — modules/$NAME imported ($(git rev-list --count "$filtered_head") commits preserved)"
