#!/usr/bin/env bash
# ==============================================================================
# install.sh — Multi-Agent Mux (MAM) Orchestration Installer (Rev.2)
# ==============================================================================
set -euo pipefail

# --- Configuration & Defaults ---
TARGET_DIR=""
REFRESH="${MAM_REFRESH:-1}"
OVERWRITE_CUSTOM="${MAM_OVERWRITE_CUSTOM:-0}"
VENV_NAME=".venv"
MIN_PYTHON_VERSION="3.9"

while [[ $# -gt 0 ]]; do
  case "$1" in
    -f|--force|--refresh-skills)
      REFRESH=1
      shift
      ;;
    --no-refresh|--offline)
      REFRESH=0
      shift
      ;;
    --overwrite-custom)
      OVERWRITE_CUSTOM=1
      shift
      ;;
    -h|--help)
      cat <<EOF
Usage: $0 [options] [target_dir]

Options:
  -f, --force, --refresh-skills  Fetch and refresh skills (now default)
  --no-refresh, --offline        Skip fetching latest assets if assets exist
  --overwrite-custom             Force overwrite user-modified skill files (backup still created)
  -h, --help                     Show this help message
EOF
      exit 0
      ;;
    *)
      if [ -z "$TARGET_DIR" ]; then
        TARGET_DIR="$1"
      else
        echo "❌ Error: Unknown argument: $1" >&2
        exit 1
      fi
      shift
      ;;
  esac
done

if [ -z "$TARGET_DIR" ]; then
  TARGET_DIR="$(pwd)"
fi

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 herdr
check_cmd python3

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

if ! python3 -c "import yaml" &>/dev/null; then
  echo "❌ Error: 'PyYAML' is not installed in system python3." >&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}"

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"
    ".agents/hooks.json"
    ".agents/hooks/loop_delegation_guard.sh"
  )
  for f in "${core_files[@]}"; do
    if [ ! -f "$dir/$f" ]; then
      return 1
    fi
  done
  return 0
}

# Fetch orchestration assets if REFRESH=1 or if core assets are missing.
if [ "$REFRESH" -eq 1 ] || [ "${MAM_SKIP_VENV:-0}" -eq 1 ] || ! check_assets_present "."; then
  echo "📥 Staging orchestration assets from Gitea repository..."
  STAGE_DIR="$(mktemp -d)"
  trap 'rm -rf "$STAGE_DIR"' EXIT

  OWNERSHIP_LIB="$STAGE_DIR/deploy/lib_ownership.sh"
  FETCH_METHOD="archive"
  if [ -d "$REPO_URL" ]; then
    echo "🌐 Copying local working tree into a staging area..."
    cp -R "$REPO_URL/." "$STAGE_DIR/"
    FETCH_METHOD="local"
  elif command -v git &>/dev/null; then
    echo "🌐 Cloning repository (shallow) into a staging area..."
    git clone --depth 1 "$REPO_URL" "$STAGE_DIR"
    FETCH_METHOD="git"
  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" \
      --exclude='*/.agents/reports/*' --exclude='*/.agents/references/*' 2>/dev/null || true
    FETCH_METHOD="archive"
  else
    echo "❌ Error: neither 'git' nor 'curl' is available to fetch the skills." >&2
    exit 1
  fi

  if [ ! -f "$OWNERSHIP_LIB" ]; then
    echo "❌ Error: missing $OWNERSHIP_LIB; refusing to install with unknown ownership rules." >&2
    exit 1
  fi
  # shellcheck source=deploy/lib_ownership.sh
  . "$OWNERSHIP_LIB"

  if ! check_assets_present "$STAGE_DIR"; then
    echo "❌ Error: fetched source is missing core runtime assets. Aborting." >&2
    exit 1
  fi

  mkdir -p .mam
  MANIFEST_FILE=".mam/install_manifest.txt"
  touch "$MANIFEST_FILE"

  # Migrate legacy root layout for remove.sh and update.sh into .mam_deploy/ if owned
  mkdir -p .mam_deploy
  for legacy_script in remove.sh update.sh; do
    if [ -f "$legacy_script" ] && grep -Fqx "$legacy_script" "$MANIFEST_FILE" 2>/dev/null; then
      mv -f "$legacy_script" ".mam_deploy/$legacy_script"
      python3 -c '
import sys
path = sys.argv[1]
old_s = sys.argv[2]
new_s = sys.argv[3]
with open(path, "r") as f:
    lines = f.readlines()
with open(path, "w") as f:
    for line in lines:
        if line.strip() == old_s:
            f.write(new_s + "\n")
        else:
            f.write(line)
' "$MANIFEST_FILE" "$legacy_script" ".mam_deploy/$legacy_script" 2>/dev/null || true
    fi
  done

  # Safe refresh & fingerprint checking logic
  TS=$(date -u +%Y%m%dT%H%M%SZ)
  FRAMEWORK_LEDGER=".mam/.framework_ledger.tmp"
  : > "$FRAMEWORK_LEDGER"

  mkdir -p .agents
  ( cd "$STAGE_DIR/.agents" && find . -type f -print ) | while IFS= read -r rel; do
    case "$rel" in
      ./reports/*|./references/*) continue ;;
      *.tmp|*.log|*.pyc|*/__pycache__/*) continue ;;
    esac

    dest=".agents/${rel#./}"
    mkdir -p "$(dirname "$dest")"

    if is_framework_owned "$dest"; then
      STAGING_FILE="$STAGE_DIR/.agents/$rel"
      printf '%s\t%s\n' "$STAGING_FILE" "$dest" >> "$FRAMEWORK_LEDGER"
      IS_REGISTRY=0
      if is_registry_file "$dest"; then IS_REGISTRY=1; fi
      ACTION=$(python3 - "$dest" "$STAGING_FILE" ".mam/asset_hashes.txt" "$OVERWRITE_CUSTOM" "$IS_REGISTRY" <<'PY'
import sys, hashlib, os

target_path, staging_path, hash_db_path, force_overwrite, is_registry = (
    sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4] == "1", sys.argv[5] == "1"
)

def file_sha(path):
    if not os.path.exists(path):
        return None
    h = hashlib.sha256()
    with open(path, "rb") as f:
        while chunk := f.read(65536):
            h.update(chunk)
    return h.hexdigest()

target_sha = file_sha(target_path)
staging_sha = file_sha(staging_path)

if target_sha is None:
    print("COPY_NEW")
    sys.exit(0)

if target_sha == staging_sha:
    print("NO_OP")
    sys.exit(0)

db_sha = None
if os.path.exists(hash_db_path):
    with open(hash_db_path, "r") as f:
        for line in f:
            parts = line.strip().split(None, 1)
            if len(parts) == 2 and parts[1] == target_path:
                db_sha = parts[0]
                break

if db_sha is None:
    print("BOOTSTRAP_OVERWRITE")
elif target_sha == db_sha:
    print("UPDATE_UNMODIFIED")
else:
    if force_overwrite:
        print("FORCE_OVERWRITE_CUSTOM")
    elif is_registry:
        print("MERGE_REGISTRY")
    else:
        print("PRESERVE_CUSTOM")
PY
)
      case "$ACTION" in
        COPY_NEW|UPDATE_UNMODIFIED|BOOTSTRAP_OVERWRITE|FORCE_OVERWRITE_CUSTOM)
          if [ "$ACTION" = "BOOTSTRAP_OVERWRITE" ] || [ "$ACTION" = "FORCE_OVERWRITE_CUSTOM" ]; then
            BACKUP_DIR=".mam/skill-backups/$TS/$(dirname "$dest")"
            mkdir -p "$BACKUP_DIR"
            cp "$dest" "$BACKUP_DIR/"
          fi
          cp -f "$STAGING_FILE" "$dest"
          if ! grep -Fqx "$dest" "$MANIFEST_FILE" 2>/dev/null; then
            echo "$dest" >> "$MANIFEST_FILE"
          fi
          ;;
        MERGE_REGISTRY)
          BACKUP_DIR=".mam/skill-backups/$TS/$(dirname "$dest")"
          mkdir -p "$BACKUP_DIR"
          cp "$dest" "$BACKUP_DIR/"
          MERGE_MSG=$(python3 - "$dest" "$STAGING_FILE" ".mam/base/$dest" <<'MERGEREG'
import json, os, sys

target_path, upstream_path, base_path = sys.argv[1], sys.argv[2], sys.argv[3]

def load(path):
    if not os.path.exists(path):
        return None
    try:
        with open(path, encoding="utf-8") as f:
            d = json.load(f)
        return d if isinstance(d, dict) else None
    except Exception:
        return None

target, upstream, base = load(target_path), load(upstream_path), load(base_path)

if target is None or upstream is None:
    print("unmergeable (not a JSON object) -- kept your file untouched")
    sys.exit(0)

merged = dict(target)
added, updated, conflicts, retired = [], [], [], []

if base is None:
    for k, v in upstream.items():
        if k not in merged:
            merged[k] = v
            added.append(k)
else:
    for k, v in upstream.items():
        if k not in base:
            if k not in merged:
                merged[k] = v
                added.append(k)
            elif merged[k] != v:
                conflicts.append(k)
        elif k not in merged:
            added.append(k)
            merged[k] = v
        elif merged[k] == base[k]:
            if merged[k] != v:
                merged[k] = v
                updated.append(k)
        elif merged[k] != v:
            conflicts.append(k)
    for k in base:
        if k not in upstream and k in merged and merged[k] == base[k]:
            del merged[k]
            retired.append(k)

if merged != target:
    tmp = target_path + ".merge.tmp"
    with open(tmp, "w", encoding="utf-8") as f:
        json.dump(merged, f, indent=2)
        f.write("\n")
    os.replace(tmp, target_path)

bits = []
for label, keys in (("added", added), ("updated", updated),
                    ("retired", retired), ("kept yours", conflicts)):
    if keys:
        bits.append("%s %s" % (label, ", ".join(sorted(keys))))
print("; ".join(bits) if bits else "already in sync")
MERGEREG
) || MERGE_MSG="merge failed -- kept your file untouched"
          echo "MERGED:$dest:$MERGE_MSG"
          if ! grep -Fqx "$dest" "$MANIFEST_FILE" 2>/dev/null; then
            echo "$dest" >> "$MANIFEST_FILE"
          fi
          ;;
        PRESERVE_CUSTOM)
          BACKUP_DIR=".mam/skill-backups/$TS/$(dirname "$dest")"
          mkdir -p "$BACKUP_DIR"
          cp "$dest" "$BACKUP_DIR/"
          echo "PRESERVED:$dest"
          ;;
        NO_OP)
          if ! grep -Fqx "$dest" "$MANIFEST_FILE" 2>/dev/null; then
            echo "$dest" >> "$MANIFEST_FILE"
          fi
          ;;
      esac
    elif [ ! -e "$dest" ]; then
      cp "$STAGE_DIR/.agents/$rel" "$dest"
      if ! grep -Fqx "$dest" "$MANIFEST_FILE" 2>/dev/null; then
        echo "$dest" >> "$MANIFEST_FILE"
      fi
    fi
  done | while IFS= read -r line; do
    if [[ "$line" == PRESERVED:* ]]; then
      echo "ℹ️  Local modification detected: ${line#PRESERVED:}" >&2
    elif [[ "$line" == MERGED:* ]]; then
      _mam_rest="${line#MERGED:}"
      echo "🔀 Registry merged: ${_mam_rest%%:*} (${_mam_rest#*:})" >&2
    fi
  done

  # Copy root docs (R-2 essential set)
  ROOT_DOCS="AGENTS.md"
  if [ "${MAM_INSTALL_DOCS:-minimal}" = "full" ]; then
    ROOT_DOCS="AGENTS.md MESSAGING.md BOOTSTRAP.md BOOTSTRAP.ko.md"
  fi
  for doc in $ROOT_DOCS; do
    if [ -f "$STAGE_DIR/$doc" ] && [ ! -e "$doc" ]; then
      cp "$STAGE_DIR/$doc" .
      echo "$doc" >> "$MANIFEST_FILE"
    fi
  done

  # Install remove.sh and update.sh into .mam_deploy/
  mkdir -p .mam_deploy
  if [ -f "$STAGE_DIR/deploy/remove.sh" ]; then
    cp "$STAGE_DIR/deploy/remove.sh" .mam_deploy/remove.sh
    chmod 0755 .mam_deploy/remove.sh
    if ! grep -Fqx ".mam_deploy/remove.sh" "$MANIFEST_FILE" 2>/dev/null; then
      echo ".mam_deploy/remove.sh" >> "$MANIFEST_FILE"
    fi
  fi

  if [ -f "$STAGE_DIR/deploy/update.sh" ]; then
    cp "$STAGE_DIR/deploy/update.sh" .mam_deploy/update.sh
    chmod 0755 .mam_deploy/update.sh
    if ! grep -Fqx ".mam_deploy/update.sh" "$MANIFEST_FILE" 2>/dev/null; then
      echo ".mam_deploy/update.sh" >> "$MANIFEST_FILE"
    fi
  fi

  if [ -f "$STAGE_DIR/.mam.env.example" ] && [ ! -e ".mam.env.example" ]; then
    cp "$STAGE_DIR/.mam.env.example" .
    echo ".mam.env.example" >> "$MANIFEST_FILE"
  fi

  if [ -f "$STAGE_DIR/deploy/INSTALL.md" ]; then
    mkdir -p .agents
    cp -f "$STAGE_DIR/deploy/INSTALL.md" .agents/INSTALL.md
    printf '%s\t%s\n' "$STAGE_DIR/deploy/INSTALL.md" ".agents/INSTALL.md" \
      >> "$FRAMEWORK_LEDGER"
    if ! grep -Fqx ".agents/INSTALL.md" "$MANIFEST_FILE" 2>/dev/null; then
      echo ".agents/INSTALL.md" >> "$MANIFEST_FILE"
    fi
  fi

  # Re-build asset_hashes.txt from the UPSTREAM copy of every framework-owned file
  python3 - .mam/asset_hashes.txt "$FRAMEWORK_LEDGER" <<'HASHDB'
import os, hashlib, sys

hash_db_path, ledger_path = sys.argv[1], sys.argv[2]

def sha(path):
    h = hashlib.sha256()
    with open(path, "rb") as f:
        while chunk := f.read(65536):
            h.update(chunk)
    return h.hexdigest()

hashes = {}
with open(ledger_path) as f:
    for line in f:
        line = line.rstrip("\n")
        if "\t" not in line:
            continue
        upstream, dest = line.split("\t", 1)
        if os.path.exists(upstream):
            hashes[dest] = sha(upstream)

with open(hash_db_path, "w") as f:
    f.writelines(sorted("%s  %s\n" % (h, d) for d, h in hashes.items()))
HASHDB

  # Snapshot registry base from upstream
  while IFS="$(printf '\t')" read -r _up _dest; do
    [ -n "${_dest:-}" ] || continue
    is_registry_file "$_dest" || continue
    [ -f "$_up" ] || continue
    mkdir -p ".mam/base/$(dirname "$_dest")"
    cp -f "$_up" ".mam/base/$_dest"
  done < "$FRAMEWORK_LEDGER"
  rm -f "$FRAMEWORK_LEDGER"

  # Record version stamp
  STAGE_COMMIT="unknown"
  if [ -d "$STAGE_DIR/.git" ]; then
    STAGE_COMMIT=$(git -C "$STAGE_DIR" rev-parse HEAD 2>/dev/null || echo "unknown")
  fi
  cat <<EOF > .mam/version.txt
source=$REPO_URL
commit=$STAGE_COMMIT
fetched_at=$TS
method=$FETCH_METHOD
EOF

  rm -rf "$STAGE_DIR"
  trap - EXIT
  echo "✅ Skills staged into workspace (user documents and custom configs preserved)."
fi

if ! check_assets_present "."; then
  echo "❌ Error: Core runtime assets missing after setup." >&2
  exit 1
fi
echo "✅ Orchestration skills present."

# --- 3. Python Virtual Environment (.venv) Setup ---
if [ "${MAM_SKIP_VENV:-0}" -eq 1 ]; then
  echo "⏩ Skipping virtualenv setup (MAM_SKIP_VENV=1)."
else
  echo "🐍 Bootstrapping Python virtual environment ($VENV_NAME)..."
  if [ ! -d "$VENV_NAME" ]; then
    python3 -m venv "$VENV_NAME"
    echo "✅ Created virtualenv at $VENV_NAME."
  else
    echo "ℹ️  Virtualenv ($VENV_NAME) already exists. Reusing."
  fi

  echo "📦 Installing/upgrading core dependencies inside $VENV_NAME..."
  # shellcheck disable=SC1091
  source "$VENV_NAME/bin/activate"
  python -m pip install --upgrade pip -q

  REQ_FILE=".agents/skills/multi-agent-mux-delegate-job/requirements.txt"
  if [ -f "$REQ_FILE" ]; then
    pip install -r "$REQ_FILE" -q
    echo "✅ Installed dependencies from $REQ_FILE."
  else
    pip install "paho-mqtt>=2.0.0" pyyaml -q
    echo "✅ Installed default fallback dependencies (paho-mqtt, pyyaml)."
  fi
  deactivate
fi

# --- 4. Environment Configuration (.mam.env) ---
echo "⚙️  Configuring environment variables..."
MAM_ENV=".mam.env"
LEGACY_ENV=".env"

if [ -f "$LEGACY_ENV" ] && [ ! -f "$MAM_ENV" ]; then
  echo "📦 Migrating existing $LEGACY_ENV to $MAM_ENV..."
  cp "$LEGACY_ENV" "$MAM_ENV"
fi

if [ ! -f "$MAM_ENV" ]; then
  echo "📝 Initializing $MAM_ENV with default orchestration configuration..."
  MAM_CLIENT_PREFIX="hermes"
  MAM_PORT="1883"
  
  cat <<EOF > "$MAM_ENV"
# ==============================================================================
# Multi-Agent Mux (MAM) Environment Configuration
# ==============================================================================
# Generated by install.sh at $(date -u +'%Y-%m-%dT%H:%M:%SZ')

MQTT_BROKER=localhost
MQTT_PORT=$MAM_PORT
MQTT_CLIENT_ID_PREFIX=$MAM_CLIENT_PREFIX
MQTT_RETRY_INTERVAL=2
MQTT_MAX_RETRIES=5

HERDR_SERVER_NAME=multi-agent-mux
HERDR_SOCKET_PATH=$HOME/.config/herdr/herdr.sock

MAM_LOG_LEVEL=INFO
MAM_EVENT_RETENTION_DAYS=7
EOF
  echo "$MAM_ENV" >> "$MANIFEST_FILE"
  echo "✅ Initialized $MAM_ENV."
else
  echo "ℹ️  $MAM_ENV already exists. Preserving existing settings."
fi

# Ensure gitignore handles MAM isolation files (R-4: managed block)
GITIGNORE=".gitignore"
MAM_GI_START="# >>> MAM managed block (managed by install.sh — do not edit) >>>"
MAM_GI_END="# <<< MAM managed block <<<"

python3 - "$GITIGNORE" "$MAM_GI_START" "$MAM_GI_END" <<'PY'
import sys, os

gi_path, start_marker, end_marker = sys.argv[1], sys.argv[2], sys.argv[3]

block_lines = [
    start_marker + "\n",
    "/.venv/\n",
    "/.mam/\n",
    "/.mam_deploy/\n",
    "/.mam.env\n",
    "/.mam.env.*\n",
    "!/.mam.env.example\n",
    "/.cache/multi-agent-mux-monitor/\n",
    "/.mam-skill-backup.*/\n",
    "CURRENT_JOB.md\n",
    end_marker + "\n"
]

lines = []
if os.path.exists(gi_path):
    with open(gi_path, "r") as f:
        lines = f.readlines()

new_lines = []
in_block = False
block_inserted = False

for line in lines:
    if line.strip() == start_marker:
        in_block = True
        if not block_inserted:
            new_lines.extend(block_lines)
            block_inserted = True
        continue
    if line.strip() == end_marker:
        in_block = False
        continue
    if not in_block:
        new_lines.append(line)

if not block_inserted:
    if new_lines and not new_lines[-1].endswith("\n"):
        new_lines[-1] += "\n"
    new_lines.extend(block_lines)

with open(gi_path, "w") as f:
    f.writelines(new_lines)
PY

if [ "${MAM_SKIP_GITIGNORE:-0}" -eq 0 ]; then
  python3 -c '
import os
if os.path.exists(".mam/install_state"):
    with open(".mam/install_state", "a") as f:
        f.write("gitignore_created=1\n")
else:
    os.makedirs(".mam", exist_ok=True)
    with open(".mam/install_state", "w") as f:
        f.write("gitignore_created=1\n")
'
fi

echo "===================================================================="
echo "🎉 Multi-Agent Mux (MAM) Installation Completed Successfully!"
echo "===================================================================="
cat <<EOF

--------------------------------------------------------------------------------
💡 Next Steps:
  1. Initialize a new isolated session:
     $ bash .agents/skills/multi-agent-mux-create/scripts/create_session.sh \\
         --workspace "$TARGET_DIR" --agent claude --role developer --isolate

  2. Monitor live agent states:
     $ bash .agents/skills/multi-agent-mux-status/scripts/status.sh

  3. Update installed skills in the future:
     $ bash .mam_deploy/update.sh
--------------------------------------------------------------------------------
EOF
