#!/usr/bin/env bash
# dual-opinion.sh — Ask Claude, Codex, and optionally Gemini the same question, then synthesize.
#
# Usage:
#   dual-opinion.sh [OPTIONS] "question text"
#   dual-opinion.sh [OPTIONS] -q question_file.md
#
# Options:
#   -f FILE     Add a context file (contents embedded in prompt; repeatable)
#   -q FILE     Read the question from a file instead of a positional argument
#   -o DIR      Output directory  (default: attic/CLAUDE/opinions/<timestamp>)
#   -m MODEL    Codex model override (e.g. o4-mini, o3)
#   -g          Include Gemini as third agent (triple opinion)
#   -G MODEL    Gemini model override (default: gemini-2.5-flash; use 'pro' for deep/multimodal)
#   -s          Synthesis only: skip agent runs, re-synthesize from latest run in -o DIR
#   -h          Show this help
#
# Output files written to the run directory:
#   prompt.md       — full prompt sent to all agents
#   claude.md       — Claude's raw response
#   codex.md        — Codex's last message
#   codex.log       — Codex stdout/progress events
#   gemini.md       — Gemini's response (if -g)
#   synthesis.md    — comparison summary (printed to terminal too)
#
# Environment overrides:
#   CLAUDE_BIN      path to claude binary  (default: /home/elphel/.local/bin/claude)
#   CODEX_BIN       path to codex binary   (default: codex)
#   GEMINI_BIN      path to gemini binary  (default: auto-detected)
#   SYNTHESIS_MODEL claude model for synthesis pass (default: sonnet)

set -euo pipefail

CLAUDE_BIN="${CLAUDE_BIN:-/home/elphel/.local/bin/claude}"
CODEX_BIN="${CODEX_BIN:-codex}"
SYNTHESIS_MODEL="${SYNTHESIS_MODEL:-sonnet}"

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WORKSPACE_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
DEFAULT_OPINIONS_DIR="$WORKSPACE_ROOT/attic/CLAUDE/opinions"

# Locate gemini binary (nvm-aware)
GEMINI_BIN="${GEMINI_BIN:-}"
if [[ -z "$GEMINI_BIN" ]]; then
  if command -v gemini &>/dev/null; then
    GEMINI_BIN="$(command -v gemini)"
  else
    NVM_GEMINI="$(ls ~/.nvm/versions/node/*/bin/gemini 2>/dev/null | tail -1 || true)"
    [[ -n "$NVM_GEMINI" ]] && GEMINI_BIN="$NVM_GEMINI"
  fi
fi

CONTEXT_FILES=()
QUESTION=""
QUESTION_FILE=""
OUTPUT_PARENT="$DEFAULT_OPINIONS_DIR"
CODEX_MODEL_ARG=""
USE_GEMINI=0
GEMINI_MODEL="gemini-2.5-flash"
SYNTHESIS_ONLY=0

usage() {
  grep '^#' "$0" | grep -v '^#!/' | sed 's/^# //' | sed 's/^#//'
  exit 0
}

while getopts "f:q:o:m:gG:sh" opt; do
  case "$opt" in
    f) CONTEXT_FILES+=("$OPTARG") ;;
    q) QUESTION_FILE="$OPTARG" ;;
    o) OUTPUT_PARENT="$OPTARG" ;;
    m) CODEX_MODEL_ARG="-m $OPTARG" ;;
    g) USE_GEMINI=1 ;;
    G) USE_GEMINI=1; GEMINI_MODEL="$OPTARG" ;;
    s) SYNTHESIS_ONLY=1 ;;
    h) usage ;;
    *) echo "Unknown flag: -$OPTARG" >&2; exit 1 ;;
  esac
done
shift $((OPTIND - 1))

# ── Validate inputs ──────────────────────────────────────────────────────────

if [[ $SYNTHESIS_ONLY -eq 0 ]]; then
  if [[ -n "$QUESTION_FILE" ]]; then
    [[ -f "$QUESTION_FILE" ]] || { echo "ERROR: question file not found: $QUESTION_FILE" >&2; exit 1; }
    QUESTION="$(cat "$QUESTION_FILE")"
  elif [[ $# -gt 0 ]]; then
    QUESTION="$*"
  else
    echo "ERROR: provide a question via -q FILE or as a positional argument." >&2
    echo "       Run with -h for usage." >&2
    exit 1
  fi
fi

# ── Prepare run directory ────────────────────────────────────────────────────

if [[ $SYNTHESIS_ONLY -eq 1 ]]; then
  # Find the most recent run under OUTPUT_PARENT
  RUN_DIR="$(ls -td "$OUTPUT_PARENT"/[0-9]* 2>/dev/null | head -1)"
  [[ -n "$RUN_DIR" ]] || { echo "ERROR: no run directories found under $OUTPUT_PARENT" >&2; exit 1; }
  echo "Re-synthesizing from: $RUN_DIR"
else
  TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
  RUN_DIR="$OUTPUT_PARENT/$TIMESTAMP"
  mkdir -p "$RUN_DIR"
fi

PROMPT_FILE="$RUN_DIR/prompt.md"
CLAUDE_OUT="$RUN_DIR/claude.md"
CODEX_OUT="$RUN_DIR/codex.md"
CODEX_LOG="$RUN_DIR/codex.log"
GEMINI_OUT="$RUN_DIR/gemini.md"
SYNTHESIS_OUT="$RUN_DIR/synthesis.md"

# ── Build prompt ─────────────────────────────────────────────────────────────

if [[ $SYNTHESIS_ONLY -eq 0 ]]; then
  {
    echo "$QUESTION"
    for f in "${CONTEXT_FILES[@]}"; do
      if [[ -f "$f" ]]; then
        echo ""
        echo "--- FILE: $f ---"
        cat "$f"
        echo "--- END FILE ---"
      else
        echo "WARNING: context file not found: $f" >&2
      fi
    done
  } > "$PROMPT_FILE"
  echo "Prompt saved to: $PROMPT_FILE"
fi

# ── Run agents in parallel ───────────────────────────────────────────────────

if [[ $SYNTHESIS_ONLY -eq 0 ]]; then
  AGENT_LIST="Claude and Codex"
  [[ $USE_GEMINI -eq 1 ]] && AGENT_LIST="Claude, Codex, and Gemini (${GEMINI_MODEL})"
  echo "Running ${AGENT_LIST} in parallel..."

  # Claude: -p for non-interactive, --no-session-persistence to avoid polluting history
  "$CLAUDE_BIN" -p "$(cat "$PROMPT_FILE")" \
    --no-session-persistence \
    > "$CLAUDE_OUT" 2>&1 &
  CLAUDE_PID=$!

  # Codex: exec with read-only sandbox, -o captures last agent message
  "$CODEX_BIN" exec \
    $CODEX_MODEL_ARG \
    -s read-only \
    -C "$WORKSPACE_ROOT" \
    -o "$CODEX_OUT" \
    "$(cat "$PROMPT_FILE")" > "$CODEX_LOG" 2>&1 &
  CODEX_PID=$!

  # Gemini (optional)
  GEMINI_PID=""
  if [[ $USE_GEMINI -eq 1 ]]; then
    [[ -n "$GEMINI_BIN" ]] || { echo "ERROR: gemini binary not found. Install: npm install -g @google/gemini-cli" >&2; exit 1; }
    "$GEMINI_BIN" -m "$GEMINI_MODEL" -p "$(cat "$PROMPT_FILE")" \
      > "$GEMINI_OUT" 2>&1 &
    GEMINI_PID=$!
  fi

  # ── Wait and check ───────────────────────────────────────────────────────────

  ERRORS=0

  if wait $CLAUDE_PID; then
    echo "  Claude: done"
  else
    echo "  Claude: exited non-zero (see $CLAUDE_OUT)" >&2
    ERRORS=$((ERRORS + 1))
  fi

  if wait $CODEX_PID; then
    echo "  Codex:  done"
  else
    echo "  Codex:  exited non-zero (see $CODEX_LOG)" >&2
    ERRORS=$((ERRORS + 1))
  fi

  if [[ -n "$GEMINI_PID" ]]; then
    if wait $GEMINI_PID; then
      echo "  Gemini: done"
    else
      echo "  Gemini: exited non-zero (see $GEMINI_OUT)" >&2
      ERRORS=$((ERRORS + 1))
    fi
  fi

  [[ -s "$CLAUDE_OUT" ]] || { echo "ERROR: Claude produced no output." >&2; ERRORS=$((ERRORS + 1)); }
  [[ -s "$CODEX_OUT"  ]] || { echo "ERROR: Codex produced no output in $CODEX_OUT" >&2; ERRORS=$((ERRORS + 1)); }
  if [[ $USE_GEMINI -eq 1 ]]; then
    [[ -s "$GEMINI_OUT" ]] || { echo "ERROR: Gemini produced no output." >&2; ERRORS=$((ERRORS + 1)); }
  fi

  if [[ $ERRORS -gt 0 ]]; then
    echo "One or more agents failed. Raw outputs in: $RUN_DIR"
    exit 1
  fi
fi

# ── Synthesis ────────────────────────────────────────────────────────────────

echo "Running synthesis..."

HAS_GEMINI=0
[[ $USE_GEMINI -eq 1 && -s "$GEMINI_OUT" ]] && HAS_GEMINI=1

if [[ $HAS_GEMINI -eq 1 ]]; then
  SYNTHESIS_PROMPT="You are synthesizing three AI agents' responses to the same software development question.
Produce exactly four sections — no preamble, no meta-commentary about the agents.

ORIGINAL QUESTION / TASK:
$(cat "$PROMPT_FILE")

--- CLAUDE'S RESPONSE ---
$(cat "$CLAUDE_OUT")
--- END CLAUDE ---

--- CODEX'S RESPONSE ---
$(cat "$CODEX_OUT")
--- END CODEX ---

--- GEMINI'S RESPONSE ---
$(cat "$GEMINI_OUT")
--- END GEMINI ---

Produce exactly:

## 1. All agree
Key points, approaches, or recommendations all three agents give.

## 2. Codex-only
What Codex proposed or flagged that the others did not.

## 3. Claude-only
What Claude proposed or flagged that the others did not.

## 4. Gemini-only
What Gemini proposed or flagged that the others did not. Include any insights leveraging Gemini's large context or multimodal capabilities.

Focus on substance. If one agent's answer is a subset of another's (not a disagreement), note that under 'All agree' rather than treating it as a difference."

else
  SYNTHESIS_PROMPT="You are synthesizing two AI agents' responses to the same software development question.
Produce exactly three sections — no preamble, no meta-commentary about the agents.

ORIGINAL QUESTION / TASK:
$(cat "$PROMPT_FILE")

--- CLAUDE'S RESPONSE ---
$(cat "$CLAUDE_OUT")
--- END CLAUDE ---

--- CODEX'S RESPONSE ---
$(cat "$CODEX_OUT")
--- END CODEX ---

Produce exactly:

## 1. Both agree
Key points, approaches, or recommendations both agents give.

## 2. Codex-only
What Codex proposed or flagged that Claude did not.

## 3. Claude-only
What Claude proposed or flagged that Codex did not.

Focus on substance. If one agent's answer is clearly a subset of the other's (not a disagreement, just less detail), note that under 'Both agree' rather than treating it as a difference."
fi

"$CLAUDE_BIN" -p "$SYNTHESIS_PROMPT" \
  --bare \
  --no-session-persistence \
  --model "$SYNTHESIS_MODEL" \
  > "$SYNTHESIS_OUT"

# ── Output ───────────────────────────────────────────────────────────────────

echo ""
if [[ $HAS_GEMINI -eq 1 ]]; then
  echo "════════════════════════════════════════"
  echo "  TRIPLE OPINION SYNTHESIS"
  echo "════════════════════════════════════════"
else
  echo "════════════════════════════════════════"
  echo "  DUAL OPINION SYNTHESIS"
  echo "════════════════════════════════════════"
fi
cat "$SYNTHESIS_OUT"
echo ""
echo "────────────────────────────────────────"
echo "Run directory: $RUN_DIR"
echo "  prompt.md    — shared prompt"
echo "  claude.md    — Claude's full response"
echo "  codex.md     — Codex's full response"
[[ $HAS_GEMINI -eq 1 ]] && echo "  gemini.md    — Gemini's full response"
echo "  synthesis.md — this summary"
