const betterSqlite3 = require('better-sqlite3');
const { Pool } = require('pg');
const path = require('path');

const sqlitePath = path.join(__dirname, '.tmp/data.db');
const sqliteDb = new betterSqlite3(sqlitePath);

const pgPool = new Pool({
  host: process.env.DATABASE_HOST || '127.0.0.1',
  port: parseInt(process.env.DATABASE_PORT || '9543', 10),
  user: process.env.DATABASE_USERNAME || 'strapi',
  password: process.env.DATABASE_PASSWORD || 'strapi_password_9000',
  database: process.env.DATABASE_NAME || 'strapi',
});

async function migrate() {
  console.log('Connecting to PostgreSQL...');
  const client = await pgPool.connect();

  try {
    console.log('Disabling constraints temporarily for migration...');
    await client.query("SET session_replication_role = 'replica';");

    // 1. Get all public tables in Postgres and TRUNCATE them
    const allTablesRes = await client.query(`
      SELECT table_name 
      FROM information_schema.tables 
      WHERE table_schema = 'public' AND table_type = 'BASE TABLE';
    `);
    const pgTables = allTablesRes.rows.map(r => r.table_name);

    for (const t of pgTables) {
      await client.query(`TRUNCATE TABLE "${t}" CASCADE;`);
    }
    console.log(`Truncated all ${pgTables.length} PostgreSQL tables.`);

    // 2. Migrate tables from SQLite
    const tablesToMigrate = [
      'strapi_database_schema',
      'strapi_migrations_internal',
      'strapi_core_store_settings',
      'i18n_locale',
      'files',
      'files_related_mph',
      'job_roles',
      'blogs',
      'blogs_author_lnk',
      'blogs_editor_lnk',
      'admin_roles',
      'admin_users',
      'admin_users_roles_lnk',
      'admin_permissions',
      'admin_permissions_role_lnk',
      'up_roles',
      'up_permissions',
      'up_permissions_role_lnk',
      'strapi_api_tokens',
      'strapi_sessions',
    ];

    for (const table of tablesToMigrate) {
      if (!pgTables.includes(table)) {
        console.log(`Table ${table} does not exist in Postgres, skipping.`);
        continue;
      }

      const colInfoRes = await client.query(
        `SELECT column_name, data_type FROM information_schema.columns WHERE table_name = $1;`,
        [table]
      );
      const colDataTypes = {};
      colInfoRes.rows.forEach(r => {
        colDataTypes[r.column_name] = r.data_type;
      });

      const rows = sqliteDb.prepare(`SELECT * FROM "${table}"`).all();
      console.log(`Migrating table: ${table} (${rows.length} rows)`);

      if (rows.length === 0) continue;

      const columns = Object.keys(rows[0]);
      const colNames = columns.map((c) => `"${c}"`).join(', ');

      for (let index = 0; index < rows.length; index++) {
        const row = rows[index];
        const values = columns.map((col) => {
          let val = row[col];
          const dt = colDataTypes[col];

          if ((dt === 'timestamp with time zone' || dt === 'timestamp without time zone') && val !== null) {
            if (typeof val === 'number' || (typeof val === 'string' && /^\d+$/.test(val))) {
              val = new Date(Number(val)).toISOString();
            }
          }

          if (dt === 'json' || dt === 'jsonb') {
            if (val === '' || val === undefined) {
              val = null;
            } else if (typeof val === 'object') {
              val = JSON.stringify(val);
            }
          }

          if (dt === 'boolean' && val !== null) {
            if (val === 1 || val === '1' || val === 'true') val = true;
            if (val === 0 || val === '0' || val === 'false') val = false;
          }

          return val;
        });

        const placeholders = values.map((_, i) => `$${i + 1}`).join(', ');
        const query = `INSERT INTO "${table}" (${colNames}) VALUES (${placeholders});`;
        await client.query(query, values);
      }

      if (columns.includes('id')) {
        const seqRes = await client.query(`
          SELECT pg_get_serial_sequence('"${table}"', 'id') AS seq;
        `);
        const seqName = seqRes.rows[0]?.seq;
        if (seqName) {
          await client.query(`
            SELECT setval('${seqName}', COALESCE((SELECT MAX(id) FROM "${table}"), 1));
          `);
        }
      }
    }

    // 3. Fix ordinals for all link tables
    console.log('Fixing ordinals for link tables...');
    await client.query(`
      UPDATE public.admin_users_roles_lnk a SET user_ord = b.inv_order FROM (
        SELECT id, ROW_NUMBER() OVER (PARTITION BY role_id ORDER BY id) as inv_order FROM public.admin_users_roles_lnk
      ) b WHERE a.id = b.id;
    `);
    await client.query(`
      UPDATE public.admin_permissions_role_lnk a SET permission_ord = b.inv_order FROM (
        SELECT id, ROW_NUMBER() OVER (PARTITION BY role_id ORDER BY id) as inv_order FROM public.admin_permissions_role_lnk
      ) b WHERE a.id = b.id;
    `);
    await client.query(`
      UPDATE public.up_permissions_role_lnk a SET permission_ord = b.inv_order FROM (
        SELECT id, ROW_NUMBER() OVER (PARTITION BY role_id ORDER BY id) as inv_order FROM public.up_permissions_role_lnk
      ) b WHERE a.id = b.id;
    `);

    console.log('Re-enabling constraints...');
    await client.query("SET session_replication_role = 'origin';");

    console.log('Migration completed successfully!');
  } catch (err) {
    console.error('Migration failed:', err);
  } finally {
    client.release();
    await pgPool.end();
    sqliteDb.close();
  }
}

migrate();
