#!/usr/bin/env bash
# ==============================================================================
# install.sh — Multi-Agent Mux (MAM) Orchestration Installer
# ==============================================================================
# Idempotent, robust installer to bootstrap MAM orchestration skills
# and Python backplane dependencies on any local workspace.
# ==============================================================================
set -euo pipefail

# --- Configuration & Defaults ---
TARGET_DIR="${1:-$(pwd)}"
VENV_NAME=".venv"
MIN_PYTHON_VERSION="3.9"

echo "===================================================================="
echo "⚡ Starting Multi-Agent Mux (MAM) Installation"
echo "📂 Target Workspace: $TARGET_DIR"
echo "===================================================================="

# --- 1. System Requirements Validation ---
echo "🔍 Checking system dependencies..."

check_cmd() {
  local cmd="$1"
  if ! command -v "$cmd" &>/dev/null; then
    echo "❌ Error: '$cmd' is not installed. Please install it first." >&2
    exit 1
  fi
}

check_cmd tmux
check_cmd python3

# Verify Python Version
PYTHON_VERSION=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
PYTHON_MAJOR="${MIN_PYTHON_VERSION%%.*}"
PYTHON_MINOR="${MIN_PYTHON_VERSION##*.}"
if python3 -c "import sys; exit(0 if sys.version_info >= ($PYTHON_MAJOR, $PYTHON_MINOR) else 1)"; then
  echo "✅ Python $PYTHON_VERSION detected."
else
  echo "❌ Error: Python version must be $MIN_PYTHON_VERSION or higher. Detected: $PYTHON_VERSION" >&2
  exit 1
fi

# Verify PyYAML (needed by system python3 for atomic state writes)
if ! python3 -c "import yaml" &>/dev/null; then
  echo "❌ Error: 'PyYAML' is not installed in the system python3. Please install it first" >&2
  echo "   (e.g., 'pip3 install PyYAML' or 'sudo apt-get install python3-yaml')." >&2
  exit 1
fi
echo "✅ PyYAML (system dependency) detected."

# --- 2. Workspace Setup ---
mkdir -p "$TARGET_DIR"
cd "$TARGET_DIR"

REPO_URL="${MAM_REPO_URL:-https://git.godopu.com/tmpl/multi-agent-mux.git}"
ARCHIVE_URL="${MAM_ARCHIVE_URL:-https://git.godopu.com/tmpl/multi-agent-mux/archive/main.tar.gz}"

# Helper to verify presence of all core runtime files.
# Keying off a set of core files helps detect and recover from partial/interrupted installations.
check_assets_present() {
  local dir="${1:-.}"
  local core_files=(
    ".agents/skills/lib.sh"
    ".agents/skills/multi-agent-mux-create/scripts/create_session.sh"
    ".agents/skills/multi-agent-mux-delegate-job/scripts/registry.py"
    ".agents/skills/multi-agent-mux-status/scripts/status.sh"
    ".agents/skills/multi-agent-mux-loop/scripts/run_loop.sh"
  )
  for f in "${core_files[@]}"; do
    if [ ! -f "$dir/$f" ]; then
      return 1
    fi
  done
  return 0
}

# Fetch the orchestration assets if missing or incomplete (for curl one-liner installs).
#
# Safety model (FW-D1): we NEVER extract the repo archive directly into the
# target. Running inside an existing project must not overwrite the target's
# own files (README.md, FUTURE_WORKS.md, …) or litter it with this repo's
# development docs. Instead we stage the download into a throwaway temp dir,
# verify it, then copy ONLY the runtime assets (.agents/, documents, .env.example)
# into the target with per-file no-clobber guards so a pre-existing target file
# always wins.
if ! check_assets_present "."; then
  echo "📥 Orchestration skills not found or incomplete. Fetching from Gitea repository..."
  STAGE_DIR="$(mktemp -d)"
  trap 'rm -rf "$STAGE_DIR"' EXIT

  if command -v git &>/dev/null; then
    echo "🌐 Cloning repository (shallow) into a staging area..."
    git clone --depth 1 "$REPO_URL" "$STAGE_DIR"
  elif command -v curl &>/dev/null; then
    echo "🌐 Downloading and extracting archive into a staging area..."
    curl -fsSL "$ARCHIVE_URL" | tar -xz --strip-components=1 -C "$STAGE_DIR"
  else
    echo "❌ Error: neither 'git' nor 'curl' is available to fetch the skills." >&2
    exit 1
  fi

  # Verify the staged tree before we trust and copy from it.
  if ! check_assets_present "$STAGE_DIR"; then
    echo "❌ Error: fetched source is missing core runtime assets. Aborting (no files copied)." >&2
    exit 1
  fi

  # Create metadata directory and initialize manifest before copying
  mkdir -p .mam
  MANIFEST_FILE=".mam/install_manifest.txt"
  touch "$MANIFEST_FILE"

  # Copy ONLY runtime assets into the target, never overwriting an existing
  # target file. We merge per-file (POSIX find + an explicit "[ ! -e ]" guard)
  # instead of `cp -n`: `cp -n` is non-portable and now prints a deprecation
  # warning on GNU coreutils 9.x, whereas the explicit guard is portable to
  # BSD/macOS and makes the no-clobber intent obvious.
  mkdir -p .agents
  ( cd "$STAGE_DIR/.agents" && find . -type f -print ) | while IFS= read -r rel; do
    dest=".agents/${rel#./}"
    if [ ! -e "$dest" ]; then
      mkdir -p "$(dirname "$dest")"
      cp "$STAGE_DIR/.agents/$rel" "$dest" || { echo "❌ Error: Failed to copy $rel" >&2; exit 1; }
      echo "$dest" >> "$MANIFEST_FILE"
    fi
  done

  # Copy non-dev documents if they don't already exist.
  # We skip dev-specific docs like README.md, DONE.md, and FUTURE_WORKS.md.
  for doc in MESSAGING.md BOOTSTRAP.md BOOTSTRAP.ko.md AGENTS.md; do
    if [ -f "$STAGE_DIR/$doc" ] && [ ! -e "$doc" ]; then
      cp "$STAGE_DIR/$doc" . || { echo "❌ Error: Failed to copy $doc" >&2; exit 1; }
      echo "$doc" >> "$MANIFEST_FILE"
    fi
  done

  if [ -f "$STAGE_DIR/deploy/remove.sh" ] && [ ! -e "remove.sh" ]; then
    cp "$STAGE_DIR/deploy/remove.sh" remove.sh || { echo "❌ Error: Failed to copy remove.sh" >&2; exit 1; }
    chmod +x remove.sh
    echo "remove.sh" >> "$MANIFEST_FILE"
  fi

  if [ -f "$STAGE_DIR/deploy/update.sh" ] && [ ! -e "update.sh" ]; then
    cp "$STAGE_DIR/deploy/update.sh" update.sh || { echo "❌ Error: Failed to copy update.sh" >&2; exit 1; }
    chmod +x update.sh
    echo "update.sh" >> "$MANIFEST_FILE"
  fi

  if [ -f "$STAGE_DIR/.env.example" ] && [ ! -e ".env.example" ]; then
    cp "$STAGE_DIR/.env.example" . || { echo "❌ Error: Failed to copy .env.example" >&2; exit 1; }
    echo ".env.example" >> "$MANIFEST_FILE"
  fi

  # Ship the user manual into the target's .agents/ (consistent with install_mam.sh)
  if [ -f "$STAGE_DIR/deploy/INSTALL.md" ]; then
    mkdir -p .agents
    if [ ! -e ".agents/INSTALL.md" ]; then
      cp "$STAGE_DIR/deploy/INSTALL.md" .agents/INSTALL.md || { echo "❌ Error: Failed to copy INSTALL.md" >&2; exit 1; }
      echo ".agents/INSTALL.md" >> "$MANIFEST_FILE"
    fi
  fi

  rm -rf "$STAGE_DIR"
  trap - EXIT
  echo "✅ Skills staged into workspace (existing files preserved)."
fi

# Sanity check: verify all core files, not just a single one — an empty or
# incomplete layout would yield a silently broken install.
if ! check_assets_present "."; then
  echo "❌ Error: Core runtime assets missing after setup. Target layout might be invalid." >&2
  exit 1
fi
echo "✅ Orchestration skills present."

echo "📂 Ensuring metadata directory structure (.mam/)..."
mkdir -p .mam/jobs .mam/delegate_job_logs

# File permission lockdown on database directory (if owned by the current user to prevent multi-user system issues)
if [ -O .mam ]; then
  chmod 0700 .mam
fi

# --- 3. Check Network File System (NFS) Warnings ---
echo "💾 Detecting file system mount type..."
if command -v df &>/dev/null && command -v mount &>/dev/null; then
  MOUNTPOINT="$(df --output=target . 2>/dev/null | tail -1 || echo "")"
  if [ -n "$MOUNTPOINT" ]; then
    if mount | grep -q "$MOUNTPOINT.*nfs\|$MOUNTPOINT.*cifs\|$MOUNTPOINT.*fuse.sshfs"; then
      echo "⚠️  WARNING: Target directory is on a network filesystem (NFS/CIFS/SSHFS)."
      echo "   SQLite WAL journaling and file locks are UNRELIABLE on network storage."
      echo "   The sqlite3 registry will fall back to 'DELETE' journaling instead of WAL."
    else
      echo "✅ File system supports WAL (Local storage detected)."
    fi
  fi
fi

# --- 4. Python Virtual Environment Setup ---
echo "🐍 Bootstrapping Python virtual environment (.venv)..."
if [ ! -d "$VENV_NAME" ]; then
  python3 -m venv "$VENV_NAME"
  echo "✅ Virtual environment created."
else
  echo "ℹ️  Virtual environment (.venv) already exists. Skipping creation."
fi

# Activate virtual environment
# shellcheck disable=SC1091
source "$VENV_NAME"/bin/activate

# Upgrade pip
pip install --upgrade pip

# Install requirements
REQ_FILE=".agents/skills/multi-agent-mux-delegate-job/requirements.txt"
if [ -f "$REQ_FILE" ]; then
  echo "📦 Installing backplane dependencies from $REQ_FILE..."
  pip install -r "$REQ_FILE"
  echo "✅ Dependencies installed successfully."
else
  echo "⚠️  WARNING: Could not find requirements file: $REQ_FILE"
  echo "   Installing default packages (paho-mqtt, pyyaml) manually..."
  pip install "paho-mqtt>=2.0.0" pyyaml
fi

# --- 5. Generate Environment Template ---
ENV_FILE=".env"
ENV_EXAMPLE=".env.example"
if [ ! -f "$ENV_FILE" ]; then
  if [ -f "$ENV_EXAMPLE" ]; then
    echo "📝 Creating configuration from $ENV_EXAMPLE..."
    cp "$ENV_EXAMPLE" "$ENV_FILE"
  else
    echo "📝 Creating default $ENV_FILE..."
    touch "$ENV_FILE"
  fi
  
  # Always append the active defaults to ensure they are set and not commented out
  cat <<EOF >> "$ENV_FILE"

# === Installer-applied active defaults ===
MQTT_BROKER=broker.hivemq.com
MQTT_PORT=1883
MQTT_TLS=0
MQTT_CLIENT_ID_PREFIX=mam-agent
TMUX_SERVER_NAME=default
EOF
  chmod 0600 "$ENV_FILE"
  echo "✅ Config file .env initialized with chmod 0600."
  
  # Record the newly created .env in the manifest
  mkdir -p .mam
  touch .mam/install_manifest.txt
  echo "$ENV_FILE" >> .mam/install_manifest.txt
else
  echo "ℹ️  $ENV_FILE already exists. Skipping config override."
fi

echo "===================================================================="
echo "🎉 Installation complete!"
echo "✨ You can now run the status or monitor skills."
echo "💡 Hint: Try executing: .venv/bin/python .agents/skills/multi-agent-mux-delegate-job/scripts/registry.py list"
echo "===================================================================="
