#!/bin/bash
# ============================================================
#  Newtation AI Presence MCP Server — Installer (macOS / Linux)
#  https://newtationco.app/mcp
# ============================================================

set -e

BOLD="\033[1m"
BLUE="\033[1;34m"
GREEN="\033[1;32m"
YELLOW="\033[1;33m"
RED="\033[1;31m"
RESET="\033[0m"

echo ""
echo -e "${BLUE}╔══════════════════════════════════════════════╗${RESET}"
echo -e "${BLUE}║  ${BOLD}Newtation AI Presence MCP Server Installer${RESET}${BLUE}  ║${RESET}"
echo -e "${BLUE}╚══════════════════════════════════════════════╝${RESET}"
echo ""

# ── Step 1: Check Python ──────────────────────────────────────
echo -e "${BOLD}Step 1/6:${RESET} Checking Python..."

PYTHON_CMD=""
if command -v python3 &>/dev/null; then
    PYTHON_CMD="python3"
elif command -v python &>/dev/null; then
    PYTHON_CMD="python"
fi

if [ -z "$PYTHON_CMD" ]; then
    echo -e "${RED}✗ Python not found.${RESET}"
    echo ""
    echo "  Please install Python 3.10 or later:"
    echo "  → macOS:  brew install python3"
    echo "  → Linux:  sudo apt install python3"
    echo "  → Or visit: https://python.org/downloads"
    echo ""
    exit 1
fi

PY_VERSION=$($PYTHON_CMD --version 2>&1 | awk '{print $2}')
echo -e "${GREEN}✓${RESET} Found $PYTHON_CMD ($PY_VERSION)"

# ── Step 2: Create install directory ──────────────────────────
echo -e "${BOLD}Step 2/6:${RESET} Setting up install directory..."

INSTALL_DIR="$HOME/.newtation-mcp"
mkdir -p "$INSTALL_DIR"

# Create virtual environment if it doesn't exist
if [ ! -d "$INSTALL_DIR/venv" ]; then
    echo "  → Creating virtual environment..."
    $PYTHON_CMD -m venv "$INSTALL_DIR/venv" || {
        echo -e "${RED}✗ Failed to create virtual environment${RESET}"
        exit 1
    }
fi

# Activate virtual environment
source "$INSTALL_DIR/venv/bin/activate" || {
    echo -e "${RED}✗ Failed to activate virtual environment${RESET}"
    exit 1
}

echo -e "${GREEN}✓${RESET} Directory: $INSTALL_DIR"

# ── Step 3: Download the MCP server ──────────────────────────
echo -e "${BOLD}Step 3/6:${RESET} Downloading MCP server..."

SERVER_URL="https://newtationco.app/downloads/newtation_lite_server.py"
SERVER_FILE="$INSTALL_DIR/newtation_lite_server.py"

if command -v curl &>/dev/null; then
    curl -fsSL "$SERVER_URL" -o "$SERVER_FILE"
elif command -v wget &>/dev/null; then
    wget -q "$SERVER_URL" -O "$SERVER_FILE"
else
    echo -e "${RED}✗ Neither curl nor wget found. Please install one and retry.${RESET}"
    exit 1
fi

echo -e "${GREEN}✓${RESET} Downloaded server to $SERVER_FILE"

# ── Step 4: Install Python dependencies ───────────────────────
echo -e "${BOLD}Step 4/6:${RESET} Installing Python dependencies (this may take 1-2 minutes)..."
echo ""

echo "  → Upgrading pip..."
python -m pip install --upgrade pip --quiet --disable-pip-version-check || echo -e "${YELLOW}!${RESET} pip upgrade had warnings - continuing..."

echo "  → Installing mcp..."
python -m pip install mcp --quiet --disable-pip-version-check || {
    echo -e "${RED}✗ Failed to install mcp${RESET}"
    exit 1
}

echo "  → Installing httpx..."
python -m pip install httpx --quiet --disable-pip-version-check || echo -e "${YELLOW}!${RESET} httpx install failed (optional)"

echo "  → Installing truststore..."
python -m pip install truststore --quiet --disable-pip-version-check || echo -e "${YELLOW}!${RESET} truststore install failed (optional)"

echo ""
echo -e "${GREEN}✓${RESET} Dependencies installed"

# ── Step 5: Get API Keys ─────────────────────────────────────
echo -e "${BOLD}Step 5/6:${RESET} Setting up API keys..."
echo ""
echo -e "  ${YELLOW}⚠  The Newtation MCP server requires API keys for web search:${RESET}"
echo ""
echo "  1. LangSearch API (Required):"
echo "     → Visit: https://langsearch.com/api-keys"
echo "     → Create free account and get your API key"
echo ""
echo "  2. Tavily API (Optional, recommended for better reliability):"
echo "     → Visit: https://tavily.com"
echo "     → Sign up and get your API key"
echo ""

# Prompt for LangSearch API key (ensure interactive input even when piped)
if [ -r /dev/tty ]; then
    read -p "  Enter your LangSearch API key (required): " LANGSEARCH_KEY < /dev/tty
else
    echo -e "${RED}  ✗ No interactive terminal available for API key input.${RESET}"
    echo "  Please run: bash -c \"\$(curl -fsSL https://newtationco.app/downloads/install_newtation.sh)\""
    exit 1
fi
while [ -z "$LANGSEARCH_KEY" ]; do
    echo -e "${RED}  ✗ LangSearch API key is required${RESET}"
    read -p "  Enter your LangSearch API key: " LANGSEARCH_KEY < /dev/tty
done

# Prompt for Tavily API key (optional)
read -p "  Enter your Tavily API key (optional, press Enter to skip): " TAVILY_KEY < /dev/tty

echo ""
echo -e "${GREEN}✓${RESET} API keys configured"

# ── Step 6: Configure Claude Desktop ─────────────────────────
echo -e "${BOLD}Step 6/6:${RESET} Configuring Claude Desktop..."

# Find Claude config path
if [ "$(uname)" = "Darwin" ]; then
    CLAUDE_CONFIG="$HOME/Library/Application Support/Claude/claude_desktop_config.json"
else
    CLAUDE_CONFIG="$HOME/.config/Claude/claude_desktop_config.json"
fi

CLAUDE_DIR=$(dirname "$CLAUDE_CONFIG")
mkdir -p "$CLAUDE_DIR"

# Use the venv python path
VENV_PYTHON="$INSTALL_DIR/venv/bin/python"

# From here on this script touches a file that holds every MCP server's
# credentials in plain text — not just ours. At the default 022 umask a new
# file lands world-readable, which on a shared box means anyone with an account
# can read someone else's API keys. Tightening the umask once is more reliable
# than remembering a chmod at each of the three places a file gets created
# below; the explicit chmods that follow are belt to this braces, because `cp`
# and an in-place rewrite can both carry a pre-existing 644 across untouched.
umask 077

if [ -f "$CLAUDE_CONFIG" ]; then
    # The backup exists so that a bad merge is recoverable this afternoon, not
    # so that every key the user has ever pasted stays on disk indefinitely.
    # Each one is a full copy of their credentials, so keep the newest few and
    # delete the rest.
    BACKUP="$CLAUDE_CONFIG.backup.$(date +%s)"
    cp "$CLAUDE_CONFIG" "$BACKUP"
    chmod 600 "$BACKUP"
    echo "  → Backed up existing config to $(basename "$BACKUP")"

    # `ls -t` is newest-first; `tail -n +4` skips the three being kept and
    # yields the rest. When the glob matches nothing `ls` complains to stderr
    # and prints no names, so the loop simply does not run — the pipeline still
    # exits 0, which is what keeps `set -e` from killing the install here.
    ls -t "$CLAUDE_CONFIG".backup.* 2>/dev/null | tail -n +4 | while IFS= read -r stale; do
        rm -f "$stale"
    done
fi

# The config is written by a real Python file that receives its inputs as
# parameters. The previous version interpolated the answers straight into a
# `python -c "..."` program, inside single-quoted Python literals — so an API
# key containing an apostrophe closed the literal it was pasted into and
# everything after it was read as Python. Corrupting the config was the good
# outcome. The Windows installer has always done it this way; this is the same
# shape, and it also replaces the second, unescaped copy of the same data that
# used to be built as a JSON heredoc for the "no config yet" case. One path
# now, and no user input ever reaches a parser as source text.
SETUP_SCRIPT="$INSTALL_DIR/_setup_config.py"

# Quoted heredoc delimiter: the shell expands nothing inside, so what lands on
# disk is exactly what is written here.
cat > "$SETUP_SCRIPT" <<'PYEOF'
import json
import os
import sys

config_path, server_path, python_path = sys.argv[1:4]

# The two keys arrive through the environment rather than argv because argv is
# public: for as long as this process lives, any user on the machine can read
# it out of `ps aux` or /proc/<pid>/cmdline. A process's environment is not
# readable that way by anyone but its owner.
langsearch_key = os.environ.get("NEWTATION_LANGSEARCH_KEY", "")
tavily_key = os.environ.get("NEWTATION_TAVILY_KEY", "")

config = {}
if os.path.exists(config_path):
    try:
        with open(config_path, "r", encoding="utf-8") as f:
            config = json.load(f)
    except Exception as e:
        # Bailing out here would strand anyone whose config is already
        # malformed — a real state, since the file is hand-edited — and the
        # backup taken moments ago is the safety net for overwriting it.
        print(f"  Warning: could not read the existing config ({e}); starting fresh")
        config = {}

# A hand-edited file can be valid JSON and still be the wrong shape.
if not isinstance(config, dict):
    config = {}
if not isinstance(config.get("mcpServers"), dict):
    config["mcpServers"] = {}

if "newtation-lite" in config["mcpServers"]:
    print("  Newtation is already configured — updating it with the new API keys")

config["mcpServers"]["newtation-lite"] = {
    "command": python_path,
    "args": [server_path],
    "env": {
        "LANGSEARCH_API_KEY": langsearch_key,
        "TAVILY_API_KEY": tavily_key,
        "LOG_LEVEL": "INFO",
    },
}

try:
    with open(config_path, "w", encoding="utf-8") as f:
        json.dump(config, f, indent=2)
    # Opening an existing file for writing leaves its mode alone, so the umask
    # set by the installer does not help for a config that already existed.
    os.chmod(config_path, 0o600)
except Exception as e:
    print(f"  ERROR: could not write the config: {e}")
    sys.exit(1)
PYEOF

# stderr is deliberately not silenced. The old call ended in `2>/dev/null`,
# which is exactly why a quoting failure could half-write someone's config and
# still report success.
if NEWTATION_LANGSEARCH_KEY="$LANGSEARCH_KEY" \
   NEWTATION_TAVILY_KEY="$TAVILY_KEY" \
   "$VENV_PYTHON" "$SETUP_SCRIPT" "$CLAUDE_CONFIG" "$SERVER_FILE" "$VENV_PYTHON"; then
    echo -e "${GREEN}✓${RESET} Added Newtation to Claude Desktop config"
else
    echo -e "${YELLOW}!${RESET} Could not configure Claude Desktop automatically."
    echo "  → Add the newtation-lite entry to this file by hand:"
    echo "    $CLAUDE_CONFIG"
    echo "  → The exact block is at https://newtationco.app/mcp"
fi

rm -f "$SETUP_SCRIPT"

# ── Done! ─────────────────────────────────────────────────────
echo ""
echo -e "${GREEN}╔══════════════════════════════════════════════╗${RESET}"
echo -e "${GREEN}║           ${BOLD}Installation Complete! 🎉${RESET}${GREEN}           ║${RESET}"
echo -e "${GREEN}╚══════════════════════════════════════════════╝${RESET}"
echo ""
echo -e "  ${BOLD}What to do next:${RESET}"
echo ""
echo -e "  1. ${BOLD}Quit Claude Desktop${RESET} completely (Cmd+Q / right-click → Quit)"
echo -e "  2. ${BOLD}Reopen Claude Desktop${RESET}"
echo -e "  3. ${BOLD}Look for 🔌 icon${RESET} - should show 'newtation-lite'"
echo -e "  4. ${BOLD}Ask Claude:${RESET} \"Check brand visibility for [your brand]\""
echo ""
echo -e "  ${BOLD}Installed to:${RESET} $INSTALL_DIR"
echo -e "  ${BOLD}Claude config:${RESET} $CLAUDE_CONFIG"
echo -e "  ${BOLD}API keys:${RESET} written into that config file"
echo ""
echo -e "  ${YELLOW}Note:${RESET} Claude Desktop reads MCP credentials from that file, so"
echo -e "  your keys are stored there in plain text. The file has been locked to"
echo -e "  your user account (mode 600), which stops other accounts on this"
echo -e "  machine from reading it — it is not encryption, and anything running"
echo -e "  as you can still read it. If this machine is shared or lost, revoke the"
echo -e "  keys at LangSearch and Tavily rather than only deleting the file."
echo -e "  To change them later, edit: $CLAUDE_CONFIG"
echo ""
echo -e "  Need help? Visit ${BLUE}https://newtationco.app/mcp${RESET}"
echo ""
