#!/usr/bin/env node
/**
 * One-shot CLI to backfill every email from configured IMAP inboxes.
 *
 * On a fresh deploy the regular incremental poller only goes back 7 days
 * (or since the last poll watermark), so brand-new installs miss historic
 * mail. This script triggers the same code path as the UI's
 * "Fetch all history" button (POST /api/email-inboxes/:id/poll {full:true})
 * for every active inbox — pulling the entire INBOX folder.
 *
 * Idempotent: ingestOneEmail() dedupes by Message-ID, so re-running on a
 * synced inbox is harmless (already-saved messages are silently skipped).
 *
 * USAGE — from the project root:
 *   node server/scripts/fetch-all-emails.cjs                   # all active inboxes
 *   node server/scripts/fetch-all-emails.cjs --inbox <id>      # one inbox by id
 *   node server/scripts/fetch-all-emails.cjs --inbox <email>   # one inbox by imap_username
 *   node server/scripts/fetch-all-emails.cjs --include-inactive# also re-enable + sync inactive ones
 *   node server/scripts/fetch-all-emails.cjs --base http://localhost:3001
 *                                                              # custom server URL (default: localhost:3001)
 *
 * REQUIREMENTS:
 *   - The backend server must be running (this script calls its HTTP API
 *     so you don't need to duplicate the IMAP/parsing logic).
 *   - JWT_SECRET must be set in env or .env (matches the value in
 *     server/index.cjs:62). The script mints a short-lived admin token.
 *   - MySQL must be reachable to list configured inboxes.
 */

// ── Lightweight .env loader (mirrors the one in server/index.cjs so this
// script doesn't depend on running the server first). Looks at project
// root + the script's directory; never overrides already-set env vars.
(() => {
  const fs = require('fs');
  const path = require('path');
  const candidates = [
    path.join(__dirname, '..', '..', '.env'),
    path.join(__dirname, '..', '.env'),
  ];
  for (const file of candidates) {
    if (!fs.existsSync(file)) continue;
    const content = fs.readFileSync(file, 'utf8');
    for (const line of content.split('\n')) {
      const m = line.match(/^([A-Z0-9_]+)\s*=\s*(.*)$/i);
      if (!m) continue;
      const key = m[1].trim();
      let val = m[2].trim();
      if (val.startsWith('"') && val.endsWith('"')) val = val.slice(1, -1);
      else if (val.startsWith("'") && val.endsWith("'")) val = val.slice(1, -1);
      if (process.env[key] === undefined) process.env[key] = val;
    }
  }
})();

const mysql = require('mysql2/promise');
const jwt = require('jsonwebtoken');

// Argv parsing — keep it tiny, no commander dep.
const args = process.argv.slice(2);
function flag(name) {
  const i = args.indexOf(name);
  if (i < 0) return null;
  return args[i + 1] ?? true;
}
const inboxArg = flag('--inbox');
const baseUrl = (flag('--base') || process.env.OPS_API_URL || 'http://localhost:3001').replace(/\/$/, '');
const includeInactive = !!flag('--include-inactive');

const JWT_SECRET = process.env.JWT_SECRET || 'easygds-ops-platform-secret-2026';

async function main() {
  const dbConfig = {
    host: process.env.DB_HOST || '127.0.0.1',
    user: process.env.DB_USER || 'root',
    password: process.env.DB_PASSWORD || '',
    database: process.env.DB_NAME || 'tripovo_support',
    timezone: 'Z',
  };
  const pool = mysql.createPool(dbConfig);

  // 1. Resolve which inboxes to process
  let where = includeInactive ? '1=1' : 'is_active = 1';
  let params = [];
  if (inboxArg && typeof inboxArg === 'string') {
    where += ' AND (id = ? OR imap_username = ?)';
    params.push(inboxArg, inboxArg);
  }
  const [inboxes] = await pool.query(
    `SELECT id, name, imap_username, is_active, last_polled_at FROM email_inboxes WHERE ${where} ORDER BY name ASC`,
    params
  );

  if (inboxes.length === 0) {
    console.log('No inboxes to process. Configured inboxes:');
    const [all] = await pool.query('SELECT id, name, imap_username, is_active FROM email_inboxes');
    for (const ib of all) {
      console.log(`  - ${ib.name} (${ib.imap_username})  active=${!!ib.is_active}  id=${ib.id}`);
    }
    await pool.end();
    process.exit(all.length === 0 ? 0 : 1);
  }

  console.log(`Backfilling ${inboxes.length} inbox(es) via ${baseUrl}\n`);

  // 2. Mint an admin JWT (script auth — short TTL so a leaked token can't
  // be reused). Same shape the server's authMiddleware expects.
  const token = jwt.sign(
    { id: 'cli-fetch-all-emails', email: 'cli@local', role: 'admin' },
    JWT_SECRET,
    { expiresIn: '30m' }
  );

  // 3. POST {full:true} to each inbox's poll endpoint and report results.
  const t0 = Date.now();
  const summary = { totalIngested: 0, totalSkipped: 0, totalErrors: 0, succeeded: 0, failed: 0 };
  for (const ib of inboxes) {
    process.stdout.write(`▶ ${ib.name.padEnd(30)} `);
    const tStart = Date.now();
    try {
      const res = await fetch(`${baseUrl}/api/email-inboxes/${encodeURIComponent(ib.id)}/poll`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
        body: JSON.stringify({ full: true }),
      });
      const json = await res.json();
      if (json.error || !res.ok) {
        console.log(`✗ FAILED — ${json.error?.message || json.error || res.status}`);
        summary.failed++;
        continue;
      }
      const r = json.data || {};
      const dur = Math.round((Date.now() - tStart) / 1000);
      console.log(`✓ fetched ${r.fetched}, ingested ${r.ingested}, skipped ${r.skipped}, errors ${r.errors}  (${dur}s)`);
      summary.totalIngested += r.ingested || 0;
      summary.totalSkipped += r.skipped || 0;
      summary.totalErrors += r.errors || 0;
      summary.succeeded++;
    } catch (e) {
      console.log(`✗ FAILED — ${e.message}`);
      summary.failed++;
    }
  }

  const totalDur = Math.round((Date.now() - t0) / 1000);
  console.log('');
  console.log(`Done in ${totalDur}s.`);
  console.log(`  inboxes succeeded: ${summary.succeeded}/${inboxes.length}`);
  console.log(`  inboxes failed:    ${summary.failed}`);
  console.log(`  total NEW emails:  ${summary.totalIngested}`);
  console.log(`  total skipped:     ${summary.totalSkipped} (already in DB by Message-ID)`);
  console.log(`  total ingest err:  ${summary.totalErrors}`);

  await pool.end();
  process.exit(summary.failed > 0 ? 1 : 0);
}

main().catch(e => {
  console.error('FATAL:', e.message);
  process.exit(1);
});
