#!/usr/bin/env bash
# Mission Control — One-Command Installer
# The mothership for your OpenClaw fleet.
#
# Usage:
#   curl -fsSL https://raw.githubusercontent.com/builderz-labs/mission-control/main/install.sh | bash
#   # or
#   bash install.sh [--docker|--local] [--port PORT] [--data-dir DIR]
#
# Installs Mission Control and optionally repairs/configures OpenClaw.

set -euo pipefail

# ── Defaults ──────────────────────────────────────────────────────────────────
MC_PORT="${MC_PORT:-3000}"
MC_DATA_DIR=""
DEPLOY_MODE=""
SKIP_OPENCLAW=false
REPO_URL="https://github.com/builderz-labs/mission-control.git"
INSTALL_DIR="${MC_INSTALL_DIR:-$(pwd)/mission-control}"

# ── Parse arguments ───────────────────────────────────────────────────────────
while [[ $# -gt 0 ]]; do
  case "$1" in
    --docker)       DEPLOY_MODE="docker"; shift ;;
    --local)        DEPLOY_MODE="local"; shift ;;
    --port)         MC_PORT="$2"; shift 2 ;;
    --data-dir)     MC_DATA_DIR="$2"; shift 2 ;;
    --skip-openclaw) SKIP_OPENCLAW=true; shift ;;
    --dir)          INSTALL_DIR="$2"; shift 2 ;;
    -h|--help)
      echo "Usage: install.sh [--docker|--local] [--port PORT] [--data-dir DIR] [--dir INSTALL_DIR] [--skip-openclaw]"
      exit 0 ;;
    *) echo "Unknown option: $1"; exit 1 ;;
  esac
done

# ── Helpers ───────────────────────────────────────────────────────────────────
info()  { echo -e "\033[1;34m[MC]\033[0m $*"; }
ok()    { echo -e "\033[1;32m[OK]\033[0m $*"; }
warn()  { echo -e "\033[1;33m[!!]\033[0m $*"; }
err()   { echo -e "\033[1;31m[ERR]\033[0m $*" >&2; }
die()   { err "$*"; exit 1; }

command_exists() { command -v "$1" &>/dev/null; }

detect_os() {
  local os arch
  os="$(uname -s)"
  arch="$(uname -m)"

  case "$os" in
    Linux)  OS="linux" ;;
    Darwin) OS="darwin" ;;
    *)      die "Unsupported OS: $os" ;;
  esac

  case "$arch" in
    x86_64|amd64)  ARCH="x64" ;;
    aarch64|arm64) ARCH="arm64" ;;
    *)             die "Unsupported architecture: $arch" ;;
  esac

  ok "Detected $OS/$ARCH"
}

check_prerequisites() {
  local has_docker=false has_node=false

  if command_exists docker && docker info &>/dev/null 2>&1; then
    has_docker=true
    ok "Docker available ($(docker --version | head -1))"
  fi

  if command_exists node; then
    local node_major
    node_major=$(node -v | sed 's/v//' | cut -d. -f1)
    if [[ "$node_major" -ge 20 ]]; then
      has_node=true
      ok "Node.js $(node -v) available"
    else
      warn "Node.js $(node -v) found but v20+ required"
    fi
  fi

  if ! $has_docker && ! $has_node; then
    die "Either Docker or Node.js 20+ is required. Install one and retry."
  fi

  # Auto-select deploy mode if not specified
  if [[ -z "$DEPLOY_MODE" ]]; then
    if $has_docker; then
      DEPLOY_MODE="docker"
      info "Auto-selected Docker deployment (use --local to override)"
    else
      DEPLOY_MODE="local"
      info "Auto-selected local deployment (Docker not available)"
    fi
  fi

  # Validate chosen mode
  if [[ "$DEPLOY_MODE" == "docker" ]] && ! $has_docker; then
    die "Docker deployment requested but Docker is not available"
  fi
  if [[ "$DEPLOY_MODE" == "local" ]] && ! $has_node; then
    die "Local deployment requested but Node.js 20+ is not available"
  fi
  if [[ "$DEPLOY_MODE" == "local" ]] && ! command_exists pnpm; then
    info "Installing pnpm via corepack..."
    corepack enable && corepack prepare pnpm@latest --activate
    ok "pnpm installed"
  fi
}

# ── Clone or update repo ─────────────────────────────────────────────────────
fetch_source() {
  if [[ -d "$INSTALL_DIR/.git" ]]; then
    info "Updating existing installation at $INSTALL_DIR..."
    cd "$INSTALL_DIR"
    git fetch --tags
    local latest_tag
    latest_tag=$(git describe --tags --abbrev=0 origin/main 2>/dev/null || echo "")
    if [[ -n "$latest_tag" ]]; then
      git checkout "$latest_tag"
      ok "Checked out $latest_tag"
    else
      git pull origin main
      ok "Updated to latest main"
    fi
  else
    info "Cloning Mission Control..."
    if command_exists git; then
      git clone --depth 1 "$REPO_URL" "$INSTALL_DIR"
      cd "$INSTALL_DIR"
      ok "Cloned to $INSTALL_DIR"
    else
      die "git is required to clone the repository"
    fi
  fi
}

# ── Generate .env ─────────────────────────────────────────────────────────────
setup_env() {
  if [[ -f "$INSTALL_DIR/.env" ]]; then
    info "Existing .env found — keeping current configuration"
    return
  fi

  info "Generating secure .env configuration..."
  bash "$INSTALL_DIR/scripts/generate-env.sh" "$INSTALL_DIR/.env"

  # Set the port if non-default
  if [[ "$MC_PORT" != "3000" ]]; then
    if [[ "$(uname)" == "Darwin" ]]; then
      sed -i '' "s|^# PORT=3000|PORT=$MC_PORT|" "$INSTALL_DIR/.env"
    else
      sed -i "s|^# PORT=3000|PORT=$MC_PORT|" "$INSTALL_DIR/.env"
    fi
  fi

  ok "Secure .env generated"
}

# ── Docker deployment ─────────────────────────────────────────────────────────
deploy_docker() {
  info "Starting Docker deployment..."

  export MC_PORT
  docker compose up -d --build

  # Wait for healthy
  info "Waiting for Mission Control to become healthy..."
  local retries=30
  while [[ $retries -gt 0 ]]; do
    if docker compose ps --format json 2>/dev/null | grep -q '"Health":"healthy"'; then
      break
    fi
    # Fallback: try HTTP check
    if curl -sf "http://localhost:$MC_PORT/login" &>/dev/null; then
      break
    fi
    sleep 2
    ((retries--))
  done

  if [[ $retries -eq 0 ]]; then
    warn "Timeout waiting for health check — container may still be starting"
    docker compose logs --tail 20
  else
    ok "Mission Control is running in Docker"
  fi
}

# ── Local deployment ──────────────────────────────────────────────────────────
deploy_local() {
  info "Starting local deployment..."

  cd "$INSTALL_DIR"
  pnpm install --frozen-lockfile 2>/dev/null || pnpm install
  ok "Dependencies installed"

  info "Building Mission Control..."
  pnpm build
  ok "Build complete"

  # Create systemd service on Linux if systemctl is available
  if [[ "$OS" == "linux" ]] && command_exists systemctl; then
    setup_systemd
  fi

  info "Starting Mission Control..."
  PORT="$MC_PORT" nohup pnpm start > "$INSTALL_DIR/.data/mc.log" 2>&1 &
  local pid=$!
  echo "$pid" > "$INSTALL_DIR/.data/mc.pid"

  sleep 3
  if kill -0 "$pid" 2>/dev/null; then
    ok "Mission Control running (PID $pid)"
  else
    err "Failed to start. Check logs: $INSTALL_DIR/.data/mc.log"
    exit 1
  fi
}

# ── Systemd service ──────────────────────────────────────────────────────────
setup_systemd() {
  local service_file="/etc/systemd/system/mission-control.service"
  if [[ -f "$service_file" ]]; then
    info "Systemd service already exists"
    return
  fi

  info "Creating systemd service..."
  local user
  user="$(whoami)"
  local node_path
  node_path="$(which node)"

  cat > /tmp/mission-control.service <<UNIT
[Unit]
Description=Mission Control - OpenClaw Agent Dashboard
After=network.target

[Service]
Type=simple
User=$user
WorkingDirectory=$INSTALL_DIR
ExecStart=$node_path $INSTALL_DIR/.next/standalone/server.js
Restart=on-failure
RestartSec=5
Environment=NODE_ENV=production
Environment=PORT=$MC_PORT
EnvironmentFile=$INSTALL_DIR/.env

[Install]
WantedBy=multi-user.target
UNIT

  if [[ "$(id -u)" -eq 0 ]]; then
    mv /tmp/mission-control.service "$service_file"
    systemctl daemon-reload
    systemctl enable mission-control
    ok "Systemd service installed and enabled"
  else
    info "Run as root to install systemd service:"
    info "  sudo mv /tmp/mission-control.service $service_file"
    info "  sudo systemctl daemon-reload && sudo systemctl enable --now mission-control"
  fi
}

# ── OpenClaw fleet check ─────────────────────────────────────────────────────
check_openclaw() {
  if $SKIP_OPENCLAW; then
    info "Skipping OpenClaw checks (--skip-openclaw)"
    return
  fi

  echo ""
  info "=== OpenClaw Fleet Check ==="

  # Check if openclaw binary exists
  if command_exists openclaw; then
    local oc_version
    oc_version="$(openclaw --version 2>/dev/null || echo 'unknown')"
    ok "OpenClaw binary found: $oc_version"
  elif command_exists clawdbot; then
    local cb_version
    cb_version="$(clawdbot --version 2>/dev/null || echo 'unknown')"
    ok "ClawdBot binary found: $cb_version (legacy)"
    warn "Consider upgrading to openclaw CLI"
  else
    info "OpenClaw CLI not found — install it to enable agent orchestration"
    info "  See: https://github.com/builderz-labs/openclaw"
    return
  fi

  # Check OpenClaw home directory
  local oc_home="${OPENCLAW_HOME:-$HOME/.openclaw}"
  if [[ -d "$oc_home" ]]; then
    ok "OpenClaw home: $oc_home"

    # Check config
    local oc_config="$oc_home/openclaw.json"
    if [[ -f "$oc_config" ]]; then
      ok "Config found: $oc_config"
    else
      warn "No openclaw.json found at $oc_config"
      info "Mission Control will create a default config on first gateway connection"
    fi

    # Check for stale PID files
    local stale_count=0
    for pidfile in "$oc_home"/*.pid "$oc_home"/pids/*.pid; do
      [[ -f "$pidfile" ]] || continue
      local pid
      pid="$(cat "$pidfile" 2>/dev/null)" || continue
      if ! kill -0 "$pid" 2>/dev/null; then
        rm -f "$pidfile"
        ((stale_count++))
      fi
    done
    if [[ $stale_count -gt 0 ]]; then
      ok "Cleaned $stale_count stale PID file(s)"
    fi

    # Check logs directory size
    local logs_dir="$oc_home/logs"
    if [[ -d "$logs_dir" ]]; then
      local logs_size
      if [[ "$(uname)" == "Darwin" ]]; then
        logs_size="$(du -sh "$logs_dir" 2>/dev/null | cut -f1)"
      else
        logs_size="$(du -sh "$logs_dir" 2>/dev/null | cut -f1)"
      fi
      info "Logs directory: $logs_size ($logs_dir)"

      # Clean old logs (> 30 days)
      local old_logs
      old_logs=$(find "$logs_dir" -name "*.log" -mtime +30 2>/dev/null | wc -l | tr -d ' ')
      if [[ "$old_logs" -gt 0 ]]; then
        find "$logs_dir" -name "*.log" -mtime +30 -delete 2>/dev/null || true
        ok "Cleaned $old_logs log file(s) older than 30 days"
      fi
    fi

    # Check workspace directory
    local workspace="$oc_home/workspace"
    if [[ -d "$workspace" ]]; then
      local agent_count
      agent_count=$(find "$workspace" -maxdepth 1 -type d 2>/dev/null | wc -l | tr -d ' ')
      ((agent_count--)) # subtract the workspace dir itself
      info "Workspace: $agent_count agent workspace(s) in $workspace"
    fi
  else
    info "OpenClaw home not found at $oc_home"
    info "Set OPENCLAW_HOME in .env to point to your OpenClaw state directory"
  fi

  # Check gateway port
  local gw_host="${OPENCLAW_GATEWAY_HOST:-127.0.0.1}"
  local gw_port="${OPENCLAW_GATEWAY_PORT:-18789}"
  if nc -z "$gw_host" "$gw_port" 2>/dev/null || (echo > "/dev/tcp/$gw_host/$gw_port") 2>/dev/null; then
    ok "Gateway reachable at $gw_host:$gw_port"
  else
    info "Gateway not reachable at $gw_host:$gw_port (start it with: openclaw gateway start)"
  fi
}

# ── Main ──────────────────────────────────────────────────────────────────────
main() {
  echo ""
  echo "  ╔══════════════════════════════════════╗"
  echo "  ║   Mission Control Installer          ║"
  echo "  ║   The mothership for your fleet      ║"
  echo "  ╚══════════════════════════════════════╝"
  echo ""

  detect_os
  check_prerequisites

  # If running from within an existing clone, use current dir
  if [[ -f "$(pwd)/package.json" ]] && grep -q '"mission-control"' "$(pwd)/package.json" 2>/dev/null; then
    INSTALL_DIR="$(pwd)"
    info "Running from existing clone at $INSTALL_DIR"
  else
    fetch_source
  fi

  # Ensure data directory exists
  mkdir -p "$INSTALL_DIR/.data"

  setup_env

  case "$DEPLOY_MODE" in
    docker) deploy_docker ;;
    local)  deploy_local ;;
    *)      die "Unknown deploy mode: $DEPLOY_MODE" ;;
  esac

  check_openclaw

  # ── Print summary ──
  echo ""
  echo "  ╔══════════════════════════════════════╗"
  echo "  ║   Installation Complete              ║"
  echo "  ╚══════════════════════════════════════╝"
  echo ""
  info "Dashboard:  http://localhost:$MC_PORT"
  info "Mode:       $DEPLOY_MODE"
  info "Data:       $INSTALL_DIR/.data/"
  echo ""
  info "Credentials are in: $INSTALL_DIR/.env"
  echo ""

  if [[ "$DEPLOY_MODE" == "docker" ]]; then
    info "Manage:"
    info "  docker compose logs -f        # view logs"
    info "  docker compose restart         # restart"
    info "  docker compose down            # stop"
  else
    info "Manage:"
    info "  cat $INSTALL_DIR/.data/mc.log  # view logs"
    info "  kill \$(cat $INSTALL_DIR/.data/mc.pid)  # stop"
  fi

  echo ""
}

main "$@"
