#!/usr/bin/env node
/**
 * Sync local MySQL (source) → RDS (target).
 * Keeps tables listed in KEEP_TARGET where RDS has richer production data.
 *
 * Usage:
 *   node scripts/sync-local-db-to-rds.mjs
 *   node scripts/sync-local-db-to-rds.mjs --dry-run
 */
import mysql from 'mysql2/promise';
import path from 'node:path';
import fs from 'node:fs';
import { fileURLToPath } from 'node:url';

const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
const dryRun = process.argv.includes('--dry-run');

function loadEnvFile(filePath) {
  if (!fs.existsSync(filePath)) return;
  for (const line of fs.readFileSync(filePath, 'utf8').split('\n')) {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith('#')) continue;
    const eq = trimmed.indexOf('=');
    if (eq < 0) continue;
    const key = trimmed.slice(0, eq).trim();
    const value = trimmed.slice(eq + 1).trim();
    if (!process.env[key]) process.env[key] = value;
  }
}

loadEnvFile(path.join(root, '../../.env.local'));
loadEnvFile(path.join(root, '.env'));

const sourceUrl =
  process.env.SYNC_SOURCE_DATABASE_URL ?? 'mysql://boot:password@127.0.0.1:3306/tkmind';
const targetUrl =
  process.env.SYNC_TARGET_DATABASE_URL ??
  process.env.PLAZA_PROD_DATABASE_URL;

if (!targetUrl) {
  console.error('缺少 SYNC_TARGET_DATABASE_URL 或 PLAZA_PROD_DATABASE_URL');
  process.exit(1);
}

/** RDS wins — do not overwrite from local. */
const KEEP_TARGET = new Set(['h5_publication_views']);

function serializeRow(row) {
  const out = {};
  for (const [key, value] of Object.entries(row)) {
    if (value instanceof Date) out[key] = value;
    else if (value !== null && typeof value === 'object') out[key] = JSON.stringify(value);
    else out[key] = value;
  }
  return out;
}

async function copyTable(source, target, table) {
  const [rows] = await source.query(`SELECT * FROM \`${table}\``);
  if (rows.length === 0) {
    if (!dryRun) await target.query(`DELETE FROM \`${table}\``).catch(() => {});
    return 0;
  }
  if (dryRun) return rows.length;

  await target.query('SET FOREIGN_KEY_CHECKS=0');
  await target.query(`DELETE FROM \`${table}\``);
  const batchSize = 200;
  let copied = 0;
  for (let i = 0; i < rows.length; i += batchSize) {
    const chunk = rows.slice(i, i + batchSize).map(serializeRow);
    const cols = Object.keys(chunk[0]);
    const placeholders = chunk.map(() => `(${cols.map(() => '?').join(', ')})`).join(', ');
    const values = chunk.flatMap((row) => cols.map((col) => row[col]));
    await target.query(
      `INSERT INTO \`${table}\` (${cols.map((c) => `\`${c}\``).join(', ')}) VALUES ${placeholders}`,
      values,
    );
    copied += chunk.length;
  }
  await target.query('SET FOREIGN_KEY_CHECKS=1');
  return copied;
}

async function main() {
  const source = await mysql.createConnection(sourceUrl);
  const target = await mysql.createConnection(targetUrl);

  const [localTables] = await source.query('SHOW TABLES');
  const [remoteTables] = await target.query('SHOW TABLES');
  const remoteSet = new Set(remoteTables.map((r) => Object.values(r)[0]));
  const tables = localTables
    .map((r) => Object.values(r)[0])
    .filter((t) => remoteSet.has(t))
    .sort();

  console.log(`源库: ${sourceUrl.replace(/:[^:@/]+@/, ':***@')}`);
  console.log(`目标: ${targetUrl.replace(/:[^:@/]+@/, ':***@')}`);
  console.log(`保留 RDS 数据（不覆盖）: ${[...KEEP_TARGET].join(', ') || '(无)'}`);
  console.log('');

  const summary = [];
  for (const table of tables) {
    if (KEEP_TARGET.has(table)) {
      const [[r]] = await target.query(`SELECT COUNT(*) AS c FROM \`${table}\``);
      summary.push({ table, action: 'keep-rds', rows: Number(r.c) });
      continue;
    }
    const [[l]] = await source.query(`SELECT COUNT(*) AS c FROM \`${table}\``);
    const localCount = Number(l.c);
    const copied = await copyTable(source, target, table);
    summary.push({ table, action: dryRun ? 'would-sync' : 'synced', rows: copied, localCount });
  }

  console.log('TABLE\tACTION\tROWS');
  for (const row of summary) {
    console.log(`${row.table}\t${row.action}\t${row.rows}`);
  }

  await source.end();
  await target.end();
  console.log(dryRun ? '\n(dry-run，未写入)' : '\n✅ 同步完成');
}

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