// Copia TODAS as linhas ja existentes de public.kv_store_7249dcd9 (local)
// para a base remota de sincronizacao (ex: cPanel), uma unica vez - so
// depois de correr isto e' que a base remota fica "a par" da local; a
// partir dai, cada escrita nova replica-se automaticamente (ver
// backend/src/repositories/kv-store.ts, mirrorToRemote).
//
// Idempotente: usa ON CONFLICT (key) DO UPDATE, por isso pode ser corrido
// mais do que uma vez sem duplicar nem falhar (ex: para recuperar uma
// falha a meio, ou para ressincronizar depois de a base remota ter estado
// em baixo durante algum tempo).
//
// Uso (a partir de backend/, com DATABASE_* e SYNC_REMOTE_DATABASE_*
// definidas no .env):
//   npm run db:backfill:remote-kv

import { config as loadEnvironment } from 'dotenv';
import { Client } from 'pg';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

const scriptDirectory = dirname(fileURLToPath(import.meta.url));
const backendDirectory = resolve(scriptDirectory, '..');

loadEnvironment({ path: resolve(backendDirectory, '.env'), override: false, quiet: true });

const BATCH_SIZE = 500;

function environmentValue(name: string): string | undefined {
  const value = process.env[name];
  return value === undefined || value === '' ? undefined : value;
}

function parseSsl(value: string | undefined): false | { rejectUnauthorized: boolean } {
  switch (value?.trim().toLowerCase()) {
    case undefined:
    case '':
    case 'false':
      return false;
    case 'require':
    case 'no-verify':
      return { rejectUnauthorized: false };
    case 'true':
      return { rejectUnauthorized: true };
    default:
      throw new Error('SYNC_REMOTE_DATABASE_SSL must be false, true, require, or no-verify.');
  }
}

function localClientFromEnvironment(): Client {
  const host = environmentValue('DATABASE_HOST') ?? '127.0.0.1';
  const port = Number(environmentValue('DATABASE_PORT') ?? '5432');
  const database = environmentValue('DATABASE_NAME') ?? 'tonline_erp_local';
  const user = environmentValue('DATABASE_USER') ?? 'postgres';
  const password = environmentValue('DATABASE_PASSWORD');

  if (!password) {
    throw new Error('DATABASE_PASSWORD nao esta definida no backend/.env.');
  }

  return new Client({
    host,
    port,
    database,
    user,
    password,
    ssl: parseSsl(environmentValue('DATABASE_SSL')),
    application_name: 'tonline-erp-backfill-remote-kv-source',
    connectionTimeoutMillis: 10_000,
  });
}

function remoteClientFromEnvironment(): Client {
  const host = environmentValue('SYNC_REMOTE_DATABASE_HOST');
  const database = environmentValue('SYNC_REMOTE_DATABASE_NAME');
  const user = environmentValue('SYNC_REMOTE_DATABASE_USER');
  const password = environmentValue('SYNC_REMOTE_DATABASE_PASSWORD');
  const port = Number(environmentValue('SYNC_REMOTE_DATABASE_PORT') ?? '5432');

  if (!host || !database || !user || !password) {
    throw new Error(
      'SYNC_REMOTE_DATABASE_HOST/NAME/USER/PASSWORD tem de estar definidas no backend/.env.',
    );
  }

  return new Client({
    host,
    port,
    database,
    user,
    password,
    ssl: parseSsl(environmentValue('SYNC_REMOTE_DATABASE_SSL')),
    application_name: 'tonline-erp-backfill-remote-kv-target',
    connectionTimeoutMillis: 10_000,
  });
}

async function main(): Promise<void> {
  const local = localClientFromEnvironment();
  const remote = remoteClientFromEnvironment();

  await local.connect();
  await remote.connect();
  console.log('Ligado as duas bases de dados.');

  try {
    const countResult = await local.query<{ total: string }>(
      'SELECT count(*)::text AS total FROM public.kv_store_7249dcd9',
    );
    const total = Number(countResult.rows[0]?.total ?? 0);
    console.log(`${total} chave(s) a copiar da base local para a remota.`);

    let copiadas = 0;
    let lastKey = '';

    // Percorre por ordem de key (paginação estável, sem depender de OFFSET
    // - importante porque a tabela pode continuar a receber escritas
    // normais da aplicação enquanto este script corre).
    for (;;) {
      const batch = await local.query<{ key: string; value: unknown }>(
        `SELECT key, value
         FROM public.kv_store_7249dcd9
         WHERE key > $1
         ORDER BY key
         LIMIT $2`,
        [lastKey, BATCH_SIZE],
      );

      if (batch.rows.length === 0) break;

      const rows = batch.rows.map(
        (row) => `{"key":${JSON.stringify(row.key)},"value":${JSON.stringify(row.value)}}`,
      );

      await remote.query(
        `INSERT INTO public.kv_store_7249dcd9 (key, value)
         SELECT batch.key, batch.value
         FROM jsonb_to_recordset($1::jsonb) AS batch(key text, value jsonb)
         ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value`,
        [`[${rows.join(',')}]`],
      );

      copiadas += batch.rows.length;
      lastKey = batch.rows[batch.rows.length - 1]!.key;
      console.log(`  ${copiadas}/${total}...`);
    }

    console.log(`Concluído: ${copiadas} chave(s) copiada(s) para a base remota.`);
  } finally {
    await local.end();
    await remote.end();
  }
}

await main();
