/**
 * One-off migration: CPC-CSD Prisma tables "Document" and "AuditLog" →
 * re-workflow tables cpc_documents and cpc_audit_logs.
 *
 * Usage:
 *   DATABASE_URL=postgres://... npm run migrate:cpc-csd
 *
 * Optional CPC_CSD_DATABASE_URL: when set, rows are read from that database
 * and written to DATABASE_URL. When unset, both use DATABASE_URL (same DB;
 * Prisma legacy tables must still exist alongside cpc_* tables).
 */
import 'dotenv/config';
import { Sequelize, QueryTypes } from 'sequelize';
import { sequelize, CpcDocument, CpcAuditLog } from '../models';

type LegacyDoc = Record<string, any>;
type LegacyLog = Record<string, any>;

async function openSource(): Promise<{ sequelize: Sequelize; close: () => Promise<void> }> {
  const url = process.env.CPC_CSD_DATABASE_URL?.trim();
  if (url) {
    const s = new Sequelize(url, {
      dialect: 'postgres',
      logging: false
    });
    return {
      sequelize: s,
      close: async () => {
        await s.close();
      }
    };
  }
  return {
    sequelize,
    close: async () => {}
  };
}

async function tableExists(client: Sequelize, tableName: string): Promise<boolean> {
  const rows = (await client.query(
    `SELECT EXISTS (
       SELECT 1 FROM information_schema.tables
       WHERE table_schema = 'public' AND table_name = :tableName
     ) AS "exists"`,
    { replacements: { tableName }, type: QueryTypes.SELECT }
  )) as { exists: boolean }[];
  return Boolean(rows[0]?.exists);
}

async function migrateDocuments(source: Sequelize): Promise<number> {
  if (!(await tableExists(source, 'Document'))) {
    console.warn('[migrate-cpc-csd] Table "Document" not found on source; skipping documents.');
    return 0;
  }

  const rows = (await source.query('SELECT * FROM "Document"', {
    type: QueryTypes.SELECT
  })) as LegacyDoc[];

  let inserted = 0;
  for (const r of rows) {
    if (!r.id) continue;
    const existing = await CpcDocument.findByPk(r.id);
    if (existing) continue;

    try {
      await CpcDocument.create({
        id: r.id,
        bookingId: r.bookingId ?? null,
        claimId: r.claimId ?? null,
        attemptNo: r.attemptNo ?? 1,
        documentType: r.documentType ?? null,
        documentGcpUrl: r.documentGcpUrl ?? null,
        provider: r.provider ?? null,
        msdPayload: r.msdPayload ?? null,
        extractedFields: r.extractedFields ?? null,
        fieldConfidence: r.fieldConfidence ?? null,
        validationStatus: r.validationStatus ?? null,
        matchPercentage: r.matchPercentage ?? null,
        mismatchReasons: r.mismatchReasons ?? null,
        fieldResults: r.fieldResults ?? null,
        ipAddress: r.ipAddress ?? null,
        createdAt: r.createdAt ? new Date(r.createdAt) : new Date()
      });
      inserted += 1;
    } catch (err: any) {
      console.error(`[migrate-cpc-csd] Skip document ${r.id}:`, err?.message || err);
    }
  }

  return inserted;
}

async function migrateAuditLogs(source: Sequelize): Promise<number> {
  if (!(await tableExists(source, 'AuditLog'))) {
    console.warn('[migrate-cpc-csd] Table "AuditLog" not found on source; skipping audit logs.');
    return 0;
  }

  const rows = (await source.query('SELECT * FROM "AuditLog"', {
    type: QueryTypes.SELECT
  })) as LegacyLog[];

  let inserted = 0;
  for (const r of rows) {
    if (!r.id || !r.documentId) continue;
    const parent = await CpcDocument.findByPk(r.documentId);
    if (!parent) {
      console.warn(`[migrate-cpc-csd] Skip audit ${r.id}: parent document ${r.documentId} missing`);
      continue;
    }
    const existingLog = await CpcAuditLog.findByPk(r.id);
    if (existingLog) continue;

    try {
      await CpcAuditLog.create({
        id: r.id,
        documentId: r.documentId,
        action: r.action,
        previousState: r.previousState ?? null,
        newState: r.newState ?? null,
        performedBy: r.performedBy ?? null,
        remarks: r.remarks ?? null,
        createdAt: r.createdAt ? new Date(r.createdAt) : new Date()
      });
      inserted += 1;
    } catch (err: any) {
      console.error(`[migrate-cpc-csd] Skip audit log ${r.id}:`, err?.message || err);
    }
  }

  return inserted;
}

async function printCounts(): Promise<void> {
  const docTotal = await CpcDocument.count();
  const logTotal = await CpcAuditLog.count();
  console.log(`[migrate-cpc-csd] Target counts: cpc_documents=${docTotal}, cpc_audit_logs=${logTotal}`);
}

async function main(): Promise<void> {
  const { sequelize: source, close } = await openSource();
  try {
    await sequelize.authenticate();
    await source.authenticate();
    console.log('[migrate-cpc-csd] Connected to target (DATABASE_URL) and source.');

    const docInserted = await migrateDocuments(source);
    const logInserted = await migrateAuditLogs(source);

    console.log(`[migrate-cpc-csd] New cpc_documents rows: ${docInserted}`);
    console.log(`[migrate-cpc-csd] New cpc_audit_logs rows: ${logInserted}`);
    await printCounts();
  } finally {
    await close();
    await sequelize.close();
  }
}

main().catch((e) => {
  console.error('[migrate-cpc-csd] Failed:', e);
  process.exit(1);
});
