/**
 * Parse JSON from LLM output, handling common issues:
 * - Markdown code fencing (```json ... ```)
 * - Prose before/after JSON
 * - Embedded JSON objects in text
 *
 * @param {string} raw - Raw LLM output
 * @returns {{ ok: true, data: any } | { ok: false, raw: string, message: string }}
 */
export function parseLLMJson(raw) {
  if (!raw || typeof raw !== 'string') {
    return { ok: false, raw, message: 'Empty or non-string input' };
  }

  // Step 1: Strip markdown code fencing
  let cleaned = raw.replace(/^```(?:json)?\s*/i, '').replace(/\s*```\s*$/, '').trim();

  // Step 2: Try direct parse
  try {
    return { ok: true, data: JSON.parse(cleaned) };
  } catch {}

  // Step 3: Try to find first {...} block (non-greedy, allows one level of nesting)
  const match = cleaned.match(/\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}/);
  if (match) {
    try {
      return { ok: true, data: JSON.parse(match[0]) };
    } catch {}
  }

  // Step 4: Try greedy match for deeply nested JSON
  const deepMatch = cleaned.match(/\{[\s\S]*\}/);
  if (deepMatch) {
    try {
      return { ok: true, data: JSON.parse(deepMatch[0]) };
    } catch {}
  }

  return { ok: false, raw, message: 'Could not extract valid JSON from response' };
}
