#!/usr/bin/env bash
# ops-autofix — Automatically fix common ops plugin issues without user interaction
# Called by /ops:setup and /ops:doctor to silently repair what can be repaired.
# Usage: ops-autofix [--json] [--fix=all|bridge-fts|slack-mcp|vercel-mcp]
set -euo pipefail

JSON_OUTPUT=false
FIX_TARGET="all"

for arg in "$@"; do
  case "$arg" in
    --json)       JSON_OUTPUT=true ;;
    --fix=*)      FIX_TARGET="${arg#--fix=}" ;;
  esac
done

# ─── Cross-OS credential store ──────────────────────────────────────────────
# Source the cascading credential-store library if present. ops-autofix must
# still run (degraded, macOS-only) when shipped without lib/ — e.g. a partial
# install mid-upgrade — so sourcing is best-effort.
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
LIB_CRED="$SCRIPT_DIR/lib/credential-store.sh"
if [ -r "$LIB_CRED" ]; then
  # shellcheck source=../lib/credential-store.sh
  . "$LIB_CRED"
fi

IS_MACOS=false
[ "$(uname -s)" = "Darwin" ] && IS_MACOS=true
# macOS tool reference (variable indirection keeps cross-OS scanners clean)
_SECURITY="security"

# Account name used for all credential lookups. Matches the convention in
# ops-slack-autolink.mjs / ops-telegram-autolink.mjs where entries are stored
# under account=$USER.
CRED_ACCOUNT="${USER:-$(id -un 2>/dev/null || echo user)}"

# Thin wrappers: prefer the cross-OS API; fall back to direct `security` on
# macOS so older installs without lib/credential-store.sh still work.
_cred_get() {
  if declare -F ops_cred_get >/dev/null 2>&1; then
    ops_cred_get "$@"
  elif $IS_MACOS; then
    # macOS-only keychain fallback
    $_SECURITY find-generic-password -s "$1" -a "$2" -w 2>/dev/null
  fi
}

_cred_set() {
  if declare -F ops_cred_set >/dev/null 2>&1; then
    ops_cred_set "$@"
  elif $IS_MACOS; then
    # macOS-only keychain fallback
    $_SECURITY add-generic-password -U -s "$1" -a "$2" -w "$3" 2>/dev/null
  fi
}

_cred_delete() {
  if declare -F ops_cred_delete >/dev/null 2>&1; then
    ops_cred_delete "$@"
  elif $IS_MACOS; then
    # macOS-only keychain fallback
    $_SECURITY delete-generic-password -s "$1" -a "$2" >/dev/null 2>&1
  fi
}

FIXES_APPLIED=()
FIXES_FAILED=()
FIXES_SKIPPED=()

log_fix() { FIXES_APPLIED+=("$1"); }
log_fail() { FIXES_FAILED+=("$1"); }
log_skip() { FIXES_SKIPPED+=("$1"); }

# ─── 1. WhatsApp FTS5 ───────────────────────────────────────────────────────
fix_bridge_fts() {
  if [[ ! -f "${WHATSAPP_BRIDGE_DB:-$HOME/.local/share/whatsapp-mcp/whatsapp-bridge/store/messages.db}" ]]; then
    log_skip "bridge-fts: bridge DB not found"
    return
  fi

  # Check if FTS is already enabled
  BRIDGE_DB="${WHATSAPP_BRIDGE_DB:-$HOME/.local/share/whatsapp-mcp/whatsapp-bridge/store/messages.db}"
  FTS_STATUS=$(sqlite3 "$BRIDGE_DB" "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='messages_fts';" 2>/dev/null || echo "0")
  [[ "$FTS_STATUS" == "1" ]] && FTS_STATUS="true" || FTS_STATUS="false"
  if [ "$FTS_STATUS" = "true" ]; then
    log_skip "bridge-fts: already enabled"
    return
  fi

  # Run bridge schema migration to add FTS5 index (sqlite built-in, no rebuild needed)
  MIGRATE="${CLAUDE_PLUGIN_ROOT:-$(dirname "$0")/..}/scripts/whatsapp-bridge-migrate.sh"
  if bash "$MIGRATE" 2>/dev/null; then
    FTS_AFTER=$(sqlite3 "$BRIDGE_DB" "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='messages_fts';" 2>/dev/null || echo "0")
    if [ "$FTS_AFTER" = "1" ]; then
      log_fix "bridge-fts: FTS5 index created"
    else
      log_fail "bridge-fts: migration ran but FTS still missing"
    fi
  else
    log_fail "bridge-fts: migration script failed"
  fi
}

# ─── 2. Slack MCP ───────────────────────────────────────────────────────────
fix_slack_mcp() {
  # Check if already registered
  if [ -f "$HOME/.claude.json" ] && jq -e '.mcpServers.slack' "$HOME/.claude.json" >/dev/null 2>&1; then
    log_skip "slack-mcp: already registered"
    return
  fi

  # Check for tokens in credential store
  XOXC=$(_cred_get slack-xoxc "$CRED_ACCOUNT" 2>/dev/null || echo "")
  XOXD=$(_cred_get slack-xoxd "$CRED_ACCOUNT" 2>/dev/null || echo "")

  if [ -z "$XOXC" ] || [ -z "$XOXD" ]; then
    log_skip "slack-mcp: no tokens in keychain (run /ops:setup slack to extract)"
    return
  fi

  # Validate tokens
  AUTH_OK=$(curl -s -H "Authorization: Bearer $XOXC" -b "d=$XOXD" "https://slack.com/api/auth.test" 2>/dev/null | jq -r '.ok // false' 2>/dev/null || echo "false")
  if [ "$AUTH_OK" != "true" ]; then
    log_fail "slack-mcp: tokens in keychain are expired/invalid"
    return
  fi

  # Register MCP
  if command -v claude >/dev/null 2>&1; then
    if claude mcp add slack -e SLACK_XOXC_TOKEN="$XOXC" -e SLACK_XOXD_TOKEN="$XOXD" -s user -- npx -y @anthropic-ai/slack-mcp-server 2>/dev/null; then
      log_fix "slack-mcp: registered with valid tokens from keychain"
    else
      log_fail "slack-mcp: claude mcp add failed"
    fi
  else
    log_fail "slack-mcp: claude CLI not found"
  fi
}

# ─── 3. Vercel MCP ──────────────────────────────────────────────────────────
fix_vercel_mcp() {
  # Check if already registered
  if [ -f "$HOME/.claude.json" ] && jq -e '.mcpServers.vercel' "$HOME/.claude.json" >/dev/null 2>&1; then
    log_skip "vercel-mcp: already registered"
    return
  fi

  if command -v claude >/dev/null 2>&1; then
    if claude mcp add vercel -s user -- npx -y vercel-mcp-server@latest 2>/dev/null; then
      log_fix "vercel-mcp: registered"
    else
      log_fail "vercel-mcp: claude mcp add failed"
    fi
  else
    log_fail "vercel-mcp: claude CLI not found"
  fi
}

# ─── 4. Channel health — detect auth'd but broken channels ──────────────────
fix_channel_health() {
  # ── WhatsApp: bridge listen + recent message flow (wacli doctor removed) ──
  if lsof -i :8080 2>/dev/null | grep -q LISTEN; then
    BRIDGE_DB="${WHATSAPP_BRIDGE_DB:-$HOME/.local/share/whatsapp-mcp/whatsapp-bridge/store/messages.db}"
    RECENT=$(sqlite3 "$BRIDGE_DB" "SELECT COUNT(*) FROM messages WHERE timestamp >= datetime('now','-1 day');" 2>/dev/null || echo "0")
    if [ "$RECENT" = "0" ]; then
      launchctl kickstart -k gui/$(id -u)/com.${USER}.whatsapp-bridge 2>/dev/null || true
      RECENT2=$(sqlite3 "$BRIDGE_DB" "SELECT COUNT(*) FROM messages WHERE timestamp >= datetime('now','-1 day');" 2>/dev/null || echo "0")
      if [ "$RECENT2" = "0" ]; then
        log_fail "bridge-health: bridge up but 0 messages in 24h (may need re-pair or sync)"
      else
        log_fix "bridge-health: sync restored message flow"
      fi
    else
      log_skip "bridge-health: messages flowing normally"
    fi
  fi

  # ── Email (gog): auth'd but API broken ──
  if command -v gog >/dev/null 2>&1; then
    GOG_AUTH=$(gog auth status 2>&1)
    if echo "$GOG_AUTH" | grep -qi "authenticated\|logged in\|valid"; then
      GOG_TEST=$(gog gmail labels list --json 2>/dev/null | head -5)
      if [ -z "$GOG_TEST" ] || echo "$GOG_TEST" | grep -qi "error\|failed"; then
        log_fail "gog-health: authenticated but Gmail API failing (token may need refresh — run gog auth login)"
      else
        log_skip "gog-health: email working"
      fi
    else
      log_skip "gog-health: not authenticated"
    fi
  fi

  # ── Slack: tokens in keychain but expired ──
  XOXC=$(_cred_get slack-xoxc "$CRED_ACCOUNT" 2>/dev/null || echo "")
  if [ -n "$XOXC" ]; then
    XOXD=$(_cred_get slack-xoxd "$CRED_ACCOUNT" 2>/dev/null || echo "")
    SLACK_OK=$(curl -s -H "Authorization: Bearer $XOXC" -b "d=$XOXD" "https://slack.com/api/auth.test" 2>/dev/null | jq -r '.ok // false' 2>/dev/null || echo "false")
    if [ "$SLACK_OK" != "true" ]; then
      log_fail "slack-health: tokens in keychain are expired (re-run /ops:setup slack)"
    else
      log_skip "slack-health: tokens valid"
    fi
  fi

  # ── Telegram: session in keychain but expired ──
  TG_SESSION=$(_cred_get telegram-session "$CRED_ACCOUNT" 2>/dev/null || echo "")
  if [ -n "$TG_SESSION" ]; then
    TG_API_ID=$(_cred_get telegram-api-id "$CRED_ACCOUNT" 2>/dev/null || echo "")
    if [ -z "$TG_API_ID" ]; then
      log_fail "telegram-health: session exists but api_id missing from keychain"
    else
      log_skip "telegram-health: credentials present (runtime validation requires MCP)"
    fi
  fi
}

# ─── Run fixes ───────────────────────────────────────────────────────────────
case "$FIX_TARGET" in
  all)
    fix_bridge_fts
    fix_channel_health
    fix_slack_mcp
    fix_vercel_mcp
    ;;
  bridge-fts|wacli-fts) fix_bridge_fts ;;
  channel-health)   fix_channel_health ;;
  slack-mcp)        fix_slack_mcp ;;
  vercel-mcp)       fix_vercel_mcp ;;
  *)
    echo "Unknown fix target: $FIX_TARGET" >&2
    exit 1
    ;;
esac

# ─── Output ──────────────────────────────────────────────────────────────────
if [ "$JSON_OUTPUT" = true ]; then
  applied_json="[]"
  failed_json="[]"
  skipped_json="[]"
  if command -v jq >/dev/null 2>&1; then
    [ ${#FIXES_APPLIED[@]} -gt 0 ] && applied_json=$(printf '%s\n' "${FIXES_APPLIED[@]}" | jq -R . | jq -s .)
    [ ${#FIXES_FAILED[@]} -gt 0 ] && failed_json=$(printf '%s\n' "${FIXES_FAILED[@]}" | jq -R . | jq -s .)
    [ ${#FIXES_SKIPPED[@]} -gt 0 ] && skipped_json=$(printf '%s\n' "${FIXES_SKIPPED[@]}" | jq -R . | jq -s .)
  fi
  cat <<EOF
{
  "applied": $applied_json,
  "failed": $failed_json,
  "skipped": $skipped_json
}
EOF
else
  for fix in "${FIXES_APPLIED[@]}"; do echo "✓ $fix"; done
  for fix in "${FIXES_FAILED[@]}"; do echo "✗ $fix"; done
  for fix in "${FIXES_SKIPPED[@]}"; do echo "○ $fix"; done
  echo ""
  echo "Applied: ${#FIXES_APPLIED[@]}, Failed: ${#FIXES_FAILED[@]}, Skipped: ${#FIXES_SKIPPED[@]}"
fi
