#!/usr/bin/env node
// Convert custom JSON (multiple root objects in one file) to CSV
// Usage: node scripts/json-to-csv.js "temp/PEPXiaoXue3_1 2.json"

const fs = require('fs');
const path = require('path');

function csvEscape(value) {
  const s = String(value ?? '');
  const needsQuotes = /[",\n\r]/.test(s) || s.startsWith(' ') || s.endsWith(' ');
  const inner = s.replaceAll('"', '""');
  return needsQuotes ? `"${inner}"` : inner;
}

function toCSV(rows, headers) {
  const lines = [headers.map(csvEscape).join(',')];
  for (const r of rows) {
    lines.push(headers.map((h) => csvEscape(r[h])).join(','));
  }
  return lines.join('\n');
}

// Parse a file that may contain:
// - a single JSON object
// - a JSON array of objects
// - multiple JSON objects concatenated (no commas, multi-line)
function parsePossiblyConcatenatedJSON(text) {
  const t = text.trim();
  if (!t) return [];
  // Try as array first
  try {
    const arr = JSON.parse(t);
    if (Array.isArray(arr)) return arr;
    if (arr && typeof arr === 'object') return [arr];
  } catch (_) {}

  // Try to split by top-level object scanning
  const objs = [];
  let depth = 0;
  let start = -1;
  let inString = false;
  let esc = false;
  for (let i = 0; i < t.length; i++) {
    const ch = t[i];
    if (inString) {
      if (esc) {
        esc = false;
      } else if (ch === '\\') {
        esc = true;
      } else if (ch === '"') {
        inString = false;
      }
      continue;
    }
    if (ch === '"') {
      inString = true;
      continue;
    }
    if (ch === '{') {
      if (depth === 0) start = i;
      depth++;
    } else if (ch === '}') {
      depth--;
      if (depth === 0 && start !== -1) {
        const slice = t.slice(start, i + 1);
        try {
          const obj = JSON.parse(slice);
          objs.push(obj);
        } catch (_) {
          // ignore parse errors for this slice
        }
        start = -1;
      }
    }
  }
  if (objs.length) return objs;

  // Fallback: try line-by-line JSON (ndjson)
  const lines = t.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
  for (const line of lines) {
    try {
      const o = JSON.parse(line);
      objs.push(o);
    } catch (_) {
      // ignore
    }
  }
  return objs;
}

async function main() {
  const inputPath = process.argv[2] || path.join('temp', 'PEPXiaoXue3_1 2.json');
  const raw = await fs.promises.readFile(inputPath, 'utf8');
  const items = parsePossiblyConcatenatedJSON(raw);
  if (!items.length) {
    console.error('No JSON objects parsed from', inputPath);
    process.exit(1);
  }

  const rows = items.map((it) => {
    const wordRank = it.wordRank ?? '';
    const headWord = it.headWord ?? '';
    const content = JSON.stringify(it.content ?? {});
    const bookId = it.bookId ?? '';
    return { wordRank, headWord, content, bookId };
  });

  const headers = ['wordRank', 'headWord', 'content', 'bookId'];
  const csv = toCSV(rows, headers);

  const dir = path.dirname(inputPath);
  const base = path.basename(inputPath).replace(/\.[^.]*$/, '');
  const outputPath = path.join(dir, `${base}.csv`);
  await fs.promises.writeFile(outputPath, csv, 'utf8');
  console.log('CSV written to', outputPath);
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});

