import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
import { generateText as generateTextSDK } from './client.js';
import { logger } from '../utils/logger.js';
import { reportMetric } from '../metrics-reporter.js';

const execFileAsync = promisify(execFile);

// CLI is broken for realistic (long) bot prompts - it silently times out with
// empty stdout when it tries unavailable tools. Keep the timeout short so we
// fall through to the SDK fast instead of making the user wait 20s.
const TIMEOUT_MS = 8_000;
const MAX_BUFFER = 4 * 1024 * 1024; // 4 MB

// Gemini CLI is agent-by-default and will try to call tools like
// `run_shell_command` for any prompt that looks like a task. In this bot we
// only want plain text generation from the provided context - so we explicitly
// disable tool use in the system instruction.
const NO_TOOLS_PREFIX = `CRITICAL INSTRUCTIONS FOR THIS RESPONSE:
- Answer ONLY from the context provided in this prompt.
- Do NOT use any tools.
- Do NOT call run_shell_command, grep_search, read_file, or any other function.
- Do NOT try to fetch live data - everything you need is already in the prompt.
- Reply with plain text only.

---

`;

async function tryCLI(prompt: string): Promise<string | null> {
  const fullPrompt = NO_TOOLS_PREFIX + prompt;
  try {
    const { stdout } = await execFileAsync(
      'gemini',
      ['--output-format', 'text', '-p', fullPrompt],
      { timeout: TIMEOUT_MS, maxBuffer: MAX_BUFFER },
    );
    return stdout.trim() || null;
  } catch (err) {
    logger.debug('gemini CLI attempt failed', { error: String(err).slice(0, 200) });
    return null;
  }
}

/**
 * Generate text via Gemini - tries the local CLI first (free, uses user's
 * subscription), falls back to the @google/generative-ai SDK when the CLI
 * returns empty stdout (which happens ~30-50% of the time because the agentic
 * CLI silently drops responses when it tries unavailable tools).
 *
 * Pass `apiKey` to enable the SDK fallback. Throws if both fail.
 */
export async function generateTextCLI(prompt: string, apiKey?: string, callType = 'general'): Promise<string> {
  const cliAnswer = await tryCLI(prompt);
  if (cliAnswer) {
    void reportMetric({ model: 'gemini-cli', call_type: callType });
    return cliAnswer;
  }

  if (!apiKey) {
    void reportMetric({ model: 'gemini-cli', call_type: callType, error: 'CLI empty and no API key' });
    throw new Error('Gemini CLI returned empty output and no GOOGLE_API_KEY fallback was provided');
  }

  logger.debug('gemini CLI empty; falling back to SDK');
  try {
    const sdkAnswer = (await generateTextSDK(prompt, apiKey)).trim();
    if (!sdkAnswer) {
      void reportMetric({ model: 'gemini-cli', call_type: callType, error: 'SDK returned empty output' });
      throw new Error('Gemini SDK also returned empty output');
    }
    void reportMetric({ model: 'gemini-cli', call_type: callType });
    return sdkAnswer;
  } catch (err) {
    void reportMetric({ model: 'gemini-cli', call_type: callType, error: String(err) });
    throw err;
  }
}
