#!/usr/bin/env bash
# memory-import.sh — Import a Neuron .neuronmem bundle onto this device
#
# Usage:
#   ./tools/memory-import.sh input.neuronmem [--passphrase "your passphrase"]
#   ./tools/memory-import.sh input.neuronmem [--dry-run]   # verify only, no changes
#
# The script will:
#   1. Decrypt and unpack the .neuronmem file
#   2. Validate the checksum and version
#   3. Back up the current snapshot.json
#   4. Stop the soul service
#   5. Replace snapshot.json
#   6. Restart the soul service
#   7. Verify the soul came back up

set -euo pipefail

# ── Config ─────────────────────────────────────────────────────────────────────
ENGRAM_SNAPSHOT="${HOME}/.neuron/engram/snapshot.json"
SOUL_SERVICE="ai.neurontechnologies.soul"
SOUL_PORT="7770"
SOUL_STARTUP_TIMEOUT=30   # seconds to wait for soul to come back

# ── Parse args ─────────────────────────────────────────────────────────────────
INPUT_PATH=""
PASSPHRASE=""
PASSPHRASE_SET=0
DRY_RUN=0

while [[ $# -gt 0 ]]; do
  case "$1" in
    --passphrase)
      PASSPHRASE="$2"
      PASSPHRASE_SET=1
      shift 2
      ;;
    --passphrase=*)
      PASSPHRASE="${1#*=}"
      PASSPHRASE_SET=1
      shift
      ;;
    --dry-run)
      DRY_RUN=1
      shift
      ;;
    -*)
      echo "Unknown option: $1" >&2
      echo "Usage: $0 input.neuronmem [--passphrase \"...\"] [--dry-run]" >&2
      exit 1
      ;;
    *)
      if [[ -z "$INPUT_PATH" ]]; then
        INPUT_PATH="$1"
      else
        echo "Unexpected argument: $1" >&2
        exit 1
      fi
      shift
      ;;
  esac
done

if [[ -z "$INPUT_PATH" ]]; then
  echo "ERROR: No input file specified." >&2
  echo "Usage: $0 input.neuronmem [--passphrase \"...\"] [--dry-run]" >&2
  exit 1
fi

if [[ ! -f "$INPUT_PATH" ]]; then
  echo "ERROR: Input file not found: $INPUT_PATH" >&2
  exit 1
fi

echo "Neuron Memory Import"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Source:   $INPUT_PATH"
echo "Target:   $ENGRAM_SNAPSHOT"
if [[ $DRY_RUN -eq 1 ]]; then
  echo "Mode:     DRY RUN (no changes will be made)"
fi
echo ""

# ── Prompt for passphrase if needed ───────────────────────────────────────────
if [[ $PASSPHRASE_SET -eq 0 ]]; then
  read -r -s -p "Enter passphrase: " PASSPHRASE
  echo ""
  if [[ -z "$PASSPHRASE" ]]; then
    echo "ERROR: Passphrase cannot be empty." >&2
    exit 1
  fi
fi

# ── Decrypt to temp dir ────────────────────────────────────────────────────────
WORK_DIR="$(mktemp -d)"
CLEANUP() {
  rm -rf "$WORK_DIR"
}
trap CLEANUP EXIT

TAR_PATH="${WORK_DIR}/bundle.tar.gz"

echo "Decrypting..."
if ! openssl enc -d -aes-256-cbc \
    -pbkdf2 \
    -iter 600000 \
    -in "$INPUT_PATH" \
    -out "$TAR_PATH" \
    -pass "pass:${PASSPHRASE}" 2>/dev/null; then
  echo "ERROR: Decryption failed. Wrong passphrase or corrupted file." >&2
  exit 1
fi
echo "  Decrypted successfully."

# ── Unpack ─────────────────────────────────────────────────────────────────────
echo "Unpacking..."
(cd "$WORK_DIR" && tar xzf "$TAR_PATH") || {
  echo "ERROR: Failed to unpack bundle. File may be corrupted." >&2
  exit 1
}

# Locate the bundle directory (neuronmem-v1/)
BUNDLE_DIR=""
for d in "${WORK_DIR}"/neuronmem-v*/; do
  if [[ -d "$d" ]]; then
    BUNDLE_DIR="$d"
    break
  fi
done

if [[ -z "$BUNDLE_DIR" ]]; then
  echo "ERROR: Bundle directory not found. Invalid .neuronmem file." >&2
  exit 1
fi

METADATA_FILE="${BUNDLE_DIR}metadata.json"
NODES_FILE="${BUNDLE_DIR}nodes.json"

if [[ ! -f "$METADATA_FILE" ]]; then
  echo "ERROR: metadata.json missing from bundle." >&2
  exit 1
fi

if [[ ! -f "$NODES_FILE" ]]; then
  echo "ERROR: nodes.json missing from bundle." >&2
  exit 1
fi

# ── Validate metadata ──────────────────────────────────────────────────────────
echo "Validating metadata..."
FORMAT_VERSION="$(python3 -c "import json; d=json.load(open('${METADATA_FILE}')); print(d.get('version','?'))")"
EXPORTED_AT="$(python3 -c "import json; d=json.load(open('${METADATA_FILE}')); print(d.get('exported_at','?'))")"
EXPECTED_COUNT="$(python3 -c "import json; d=json.load(open('${METADATA_FILE}')); print(d.get('node_count','?'))")"
STORED_CHECKSUM="$(python3 -c "import json; d=json.load(open('${METADATA_FILE}')); print(d.get('sha256','?'))")"
SOURCE_HOST="$(python3 -c "import json; d=json.load(open('${METADATA_FILE}')); print(d.get('source_host','?'))")"

echo "  Format version: ${FORMAT_VERSION}"
echo "  Exported at:    ${EXPORTED_AT}"
echo "  Source host:    ${SOURCE_HOST}"
echo "  Expected nodes: ${EXPECTED_COUNT}"

if [[ "$FORMAT_VERSION" != "1" ]]; then
  echo "ERROR: Unsupported bundle format version: ${FORMAT_VERSION}" >&2
  echo "       This tool supports version 1 only." >&2
  exit 1
fi

# ── Validate checksum ──────────────────────────────────────────────────────────
echo "Verifying checksum..."
ACTUAL_CHECKSUM="$(openssl dgst -sha256 "$NODES_FILE" | awk '{print $NF}')"

if [[ "$ACTUAL_CHECKSUM" != "$STORED_CHECKSUM" ]]; then
  echo "ERROR: Checksum mismatch!" >&2
  echo "  Expected: ${STORED_CHECKSUM}" >&2
  echo "  Got:      ${ACTUAL_CHECKSUM}" >&2
  echo "  The bundle may be corrupted." >&2
  exit 1
fi
echo "  Checksum OK: ${ACTUAL_CHECKSUM:0:16}..."

# ── Verify node count ──────────────────────────────────────────────────────────
echo "Verifying node count..."
ACTUAL_COUNT="$(python3 -c "
import json
with open('${NODES_FILE}') as f:
    d = json.load(f)
nodes = d.get('nodes', d if isinstance(d, list) else [])
print(len(nodes) if isinstance(nodes, list) else len(nodes))
" 2>/dev/null || echo "unknown")"

echo "  Found ${ACTUAL_COUNT} nodes (expected ${EXPECTED_COUNT})"

if [[ "$ACTUAL_COUNT" != "$EXPECTED_COUNT" && "$EXPECTED_COUNT" != "unknown" ]]; then
  echo "WARNING: Node count mismatch (expected ${EXPECTED_COUNT}, found ${ACTUAL_COUNT})." >&2
  echo "         Proceeding anyway — count may differ if nodes were deduplicated." >&2
fi

# ── Dry run exit ───────────────────────────────────────────────────────────────
if [[ $DRY_RUN -eq 1 ]]; then
  echo ""
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  echo "DRY RUN complete. Bundle is valid."
  echo "  Nodes: ${ACTUAL_COUNT}"
  echo "  Checksum: verified"
  echo "  Run without --dry-run to import."
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  exit 0
fi

# ── Safety confirmation ────────────────────────────────────────────────────────
echo ""
echo "WARNING: This will replace your current Neuron memory store."
echo "  Current snapshot: $ENGRAM_SNAPSHOT"
echo "  A backup will be created before replacing."
echo ""
read -r -p "Type 'yes' to continue: " CONFIRM
if [[ "$CONFIRM" != "yes" ]]; then
  echo "Aborted."
  exit 0
fi

# ── Backup existing snapshot ───────────────────────────────────────────────────
BACKUP_TIMESTAMP="$(date -u +"%Y%m%dT%H%M%SZ")"
ENGRAM_DIR="$(dirname "$ENGRAM_SNAPSHOT")"
BACKUP_PATH="${HOME}/.neuron/engram-backup-${BACKUP_TIMESTAMP}.tar.gz"

echo ""
echo "Backing up current snapshot..."
if [[ -f "$ENGRAM_SNAPSHOT" ]]; then
  (cd "$HOME/.neuron" && tar czf "$BACKUP_PATH" "$(basename "$ENGRAM_DIR")/snapshot.json" 2>/dev/null) || \
  cp "$ENGRAM_SNAPSHOT" "${ENGRAM_SNAPSHOT}.backup-${BACKUP_TIMESTAMP}"
  echo "  Backup: $BACKUP_PATH"
else
  echo "  No existing snapshot to back up."
fi

# ── Stop soul service ──────────────────────────────────────────────────────────
echo "Stopping soul service (${SOUL_SERVICE})..."
launchctl stop "$SOUL_SERVICE" 2>/dev/null || true
# Also stop engram service if running
launchctl stop "ai.neuron.engram" 2>/dev/null || true
sleep 2
echo "  Soul stopped."

# ── Replace snapshot.json ──────────────────────────────────────────────────────
echo "Installing new snapshot..."
cp "$NODES_FILE" "$ENGRAM_SNAPSHOT"
echo "  snapshot.json replaced ($(du -sh "$ENGRAM_SNAPSHOT" | cut -f1))"

# ── Restart soul service ───────────────────────────────────────────────────────
echo "Restarting soul service..."
launchctl start "$SOUL_SERVICE" 2>/dev/null || true
launchctl start "ai.neuron.engram" 2>/dev/null || true

# ── Wait for soul to come up ───────────────────────────────────────────────────
echo "Waiting for soul to come up on port ${SOUL_PORT}..."
ELAPSED=0
SOUL_UP=0
while [[ $ELAPSED -lt $SOUL_STARTUP_TIMEOUT ]]; do
  if curl -sf "http://localhost:${SOUL_PORT}/" > /dev/null 2>&1; then
    SOUL_UP=1
    break
  fi
  # Try a known endpoint that returns any response (even 404 means it's up)
  HTTP_CODE="$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${SOUL_PORT}/api/neuron/memory" 2>/dev/null || echo "000")"
  if [[ "$HTTP_CODE" != "000" ]]; then
    SOUL_UP=1
    break
  fi
  sleep 1
  ELAPSED=$((ELAPSED + 1))
done

if [[ $SOUL_UP -eq 1 ]]; then
  echo "  Soul is up (responded in ${ELAPSED}s)."
else
  echo "  WARNING: Soul did not respond within ${SOUL_STARTUP_TIMEOUT}s."
  echo "  The service may still be starting. Check: launchctl list | grep soul"
fi

# ── Final report ───────────────────────────────────────────────────────────────
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Import complete."
echo "  Nodes imported: ${ACTUAL_COUNT}"
echo "  Exported at:    ${EXPORTED_AT}"
echo "  Source host:    ${SOURCE_HOST}"
echo "  Backup:         ${BACKUP_PATH}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
