#!/usr/bin/env bash
#
# Connect DataForSEO to OpenAI Codex (Mac/Linux).
#
# What this does:
#   1. Prompts for your DataForSEO API login + API password (the ones
#      shown under "API Access" on the DataForSEO dashboard — NOT your
#      regular dashboard password).
#   2. Verifies the credentials work by hitting a free DataForSEO endpoint.
#   3. Writes an MCP server block to ~/.codex/config.toml that points
#      Codex at DataForSEO's hosted MCP server with your credentials.
#   4. Tells you what to do next.
#
# What this does NOT do:
#   - It does not install Codex itself. Install Codex first if you don't
#     have it: https://developers.openai.com/codex/cli
#   - It does not store anything on a server we run. Your credentials
#     live only on your machine in ~/.codex/config.toml, mode 600.
#
# Re-running this is safe. It overwrites the [mcp_servers.dataforseo]
# block in your config and keeps a timestamped backup of the previous
# version.

set -euo pipefail

CONFIG_DIR="${HOME}/.codex"
CONFIG_FILE="${CONFIG_DIR}/config.toml"
MCP_URL="https://mcp.dataforseo.com/mcp"
VERIFY_URL="https://api.dataforseo.com/v3/appendix/user_data"

# Colors only if stdout is a terminal.
if [ -t 1 ]; then
  BOLD=$'\033[1m'; DIM=$'\033[2m'; RED=$'\033[31m'; GREEN=$'\033[32m'
  YELLOW=$'\033[33m'; RESET=$'\033[0m'
else
  BOLD=''; DIM=''; RED=''; GREEN=''; YELLOW=''; RESET=''
fi

say()  { printf "%s\n" "$*"; }
ok()   { printf "${GREEN}✓${RESET} %s\n" "$*"; }
warn() { printf "${YELLOW}!${RESET} %s\n" "$*"; }
err()  { printf "${RED}✗${RESET} %s\n" "$*" 1>&2; }

say "${BOLD}Connect DataForSEO to Codex${RESET}"
say ""
say "Get your API credentials from the DataForSEO dashboard:"
say "  ${DIM}https://app.dataforseo.com/api-access${RESET}"
say ""
say "These are your API login + API password (not your regular login)."
say ""

# Read credentials. Login is plain prompt, password is silent.
printf "DataForSEO API login: "
read -r DFS_USER
if [ -z "${DFS_USER}" ]; then
  err "API login can't be empty."
  exit 1
fi

printf "DataForSEO API password: "
# read -s suppresses echo on bash; add newline after.
read -rs DFS_PASS
echo
if [ -z "${DFS_PASS}" ]; then
  err "API password can't be empty."
  exit 1
fi

# Build the Basic auth header value once. Strip any newlines from base64.
AUTH_B64="$(printf '%s:%s' "${DFS_USER}" "${DFS_PASS}" | base64 | tr -d '\n')"

say ""
say "Verifying credentials against DataForSEO..."

# Hit a free user_data endpoint. 200 = creds are valid + account has API
# access. 401 = wrong creds. Anything else = transient or unexpected.
HTTP_CODE="$(
  curl -sS -o /tmp/dfs-codex-verify.json -w '%{http_code}' \
    -H "Authorization: Basic ${AUTH_B64}" \
    -H "Content-Type: application/json" \
    "${VERIFY_URL}" \
  || echo "000"
)"

case "${HTTP_CODE}" in
  200)
    ok "Credentials verified."
    ;;
  401|403)
    err "DataForSEO rejected those credentials (HTTP ${HTTP_CODE})."
    err "Double-check that you used API login + API password from the"
    err "API Access page, not your regular dashboard login."
    rm -f /tmp/dfs-codex-verify.json
    exit 1
    ;;
  000)
    err "Couldn't reach DataForSEO. Check your internet connection."
    exit 1
    ;;
  *)
    err "Unexpected response from DataForSEO (HTTP ${HTTP_CODE})."
    err "Response saved to /tmp/dfs-codex-verify.json"
    exit 1
    ;;
esac
rm -f /tmp/dfs-codex-verify.json

# Make sure ~/.codex exists and is mode 700.
mkdir -p "${CONFIG_DIR}"
chmod 700 "${CONFIG_DIR}"

# If a config file already exists, back it up + strip any prior
# [mcp_servers.dataforseo] block before we append the new one. The
# strip uses awk so we don't have to fight with multi-line regex
# semantics across bash versions.
if [ -f "${CONFIG_FILE}" ]; then
  BACKUP="${CONFIG_FILE}.bak.$(date +%Y%m%d%H%M%S)"
  cp "${CONFIG_FILE}" "${BACKUP}"
  ok "Backed up existing config to ${BACKUP}"

  TMP="$(mktemp)"
  # Drop any line inside a [mcp_servers.dataforseo] or
  # [mcp_servers.dataforseo.<anything>] section. We stop dropping when
  # we hit the next top-level section header.
  awk '
    BEGIN { skip = 0 }
    /^\[mcp_servers\.dataforseo(\.|\])/ { skip = 1; next }
    /^\[/                                  { skip = 0 }
    skip == 0                              { print }
  ' "${CONFIG_FILE}" > "${TMP}"
  mv "${TMP}" "${CONFIG_FILE}"
fi

# Append the new DataForSEO MCP block. We use the hosted streamable
# HTTP endpoint (no Node.js or local server needed). Authorization is
# Basic auth carrying base64(login:password).
{
  # Make sure the previous content ends with a newline before we
  # append a new section header. Avoids `[foo]` accidentally joining
  # the last line of the previous section.
  if [ -s "${CONFIG_FILE}" ] && [ -n "$(tail -c 1 "${CONFIG_FILE}" 2>/dev/null)" ]; then
    printf "\n"
  fi
  cat <<EOF
[mcp_servers.dataforseo]
url = "${MCP_URL}"
tool_timeout_sec = 120
default_tools_approval_mode = "prompt"

[mcp_servers.dataforseo.http_headers]
Authorization = "Basic ${AUTH_B64}"
EOF
} >> "${CONFIG_FILE}"

chmod 600 "${CONFIG_FILE}"

ok "Wrote DataForSEO config to ${CONFIG_FILE}"

say ""
warn "Security note: your DataForSEO API password is stored in plain"
warn "(base64-encoded, which is reversible) at ${CONFIG_FILE}."
warn "Treat that file like a saved password. If your laptop is ever"
warn "lost or shared, revoke + regenerate the API password from the"
warn "DataForSEO dashboard."
say ""
say "${BOLD}Next steps:${RESET}"
say "  1. Restart Codex (close + reopen the CLI or IDE extension)."
say "  2. Inside Codex, type:  /mcp"
say "  3. You should see ${BOLD}dataforseo${RESET} in the connected servers list."
say ""
say "Test prompt:"
say '  Use DataForSEO to get the top 10 Google organic results for'
say '  "best crm for agencies" in the US, desktop, English. Return'
say '  domains, titles, and URLs. Do not dump the raw payload.'
say ""
ok "Done."
