/**
 * IT0 Database Migration Runner
 *
 * Usage:
 *   npx ts-node packages/shared/database/src/run-migrations.ts [--seed] [--tenant <id>]
 *
 * Options:
 *   --seed           Also run seed data after migrations
 *   --tenant <id>    Create/migrate a specific tenant schema (e.g., t001)
 *   --all-tenants    Migrate all existing tenants from it0_shared.tenants
 *
 * Environment variables: DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD, DB_DATABASE
 */

import { Client } from 'pg';
import * as fs from 'fs';
import * as path from 'path';
import * as dotenv from 'dotenv';

dotenv.config({ path: path.resolve(__dirname, '../../../../.env') });

// ---------------------------------------------------------------------------
// Config
// ---------------------------------------------------------------------------

const DB_CONFIG = {
  host: process.env.DB_HOST || 'localhost',
  port: parseInt(process.env.DB_PORT || '5432', 10),
  user: process.env.DB_USERNAME || 'it0',
  password: process.env.DB_PASSWORD || 'it0_dev',
  database: process.env.DB_DATABASE || 'it0',
};

const MIGRATIONS_DIR = path.resolve(__dirname, './migrations');

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function log(msg: string) {
  const ts = new Date().toISOString().slice(11, 19);
  console.log(`[${ts}] ${msg}`);
}

async function createClient(): Promise<Client> {
  const client = new Client(DB_CONFIG);
  await client.connect();
  return client;
}

async function runSqlFile(client: Client, filePath: string, replacements?: Record<string, string>) {
  let sql = fs.readFileSync(filePath, 'utf-8');
  if (replacements) {
    for (const [key, value] of Object.entries(replacements)) {
      sql = sql.replace(new RegExp(key.replace(/[{}]/g, '\\$&'), 'g'), value);
    }
  }
  await client.query(sql);
}

// ---------------------------------------------------------------------------
// Migration steps
// ---------------------------------------------------------------------------

async function runSharedSchema(client: Client) {
  log('Running 001-create-shared-schema.sql ...');
  await runSqlFile(client, path.join(MIGRATIONS_DIR, '001-create-shared-schema.sql'));
  log('Shared schema created.');

  log('Running 005-create-billing-tables.sql ...');
  await runSqlFile(client, path.join(MIGRATIONS_DIR, '005-create-billing-tables.sql'));
  log('Billing tables created.');

  log('Running 010-create-presence-tables.sql ...');
  await runSqlFile(client, path.join(MIGRATIONS_DIR, '010-create-presence-tables.sql'));
  log('Presence tables created.');
}

async function runTenantSchema(client: Client, tenantId: string) {
  const schemaName = `it0_t_${tenantId}`;
  log(`Creating tenant schema: ${schemaName} ...`);

  // Run base tenant tables (002)
  await runSqlFile(
    client,
    path.join(MIGRATIONS_DIR, '002-create-tenant-schema-template.sql'),
    { '{TENANT_ID}': tenantId },
  );

  // Run additional tables (003)
  await runSqlFile(
    client,
    path.join(MIGRATIONS_DIR, '003-add-missing-tables.sql'),
    { '{SCHEMA}': schemaName },
  );

  // Run conversation messages table (004)
  await runSqlFile(
    client,
    path.join(MIGRATIONS_DIR, '004-add-conversation-messages.sql'),
    { '{SCHEMA}': schemaName },
  );

  log(`Tenant schema ${schemaName} ready.`);
}

async function getAllTenantIds(client: Client): Promise<string[]> {
  const result = await client.query('SELECT id FROM it0_shared.tenants ORDER BY id');
  return result.rows.map((r: { id: string }) => r.id);
}

// ---------------------------------------------------------------------------
// Seed data
// ---------------------------------------------------------------------------

async function runSeed(client: Client, tenantId: string) {
  const seedFile = path.join(__dirname, 'seeds', 'seed.sql');
  if (!fs.existsSync(seedFile)) {
    log('No seed file found, skipping.');
    return;
  }
  const schemaName = `it0_t_${tenantId}`;
  log(`Seeding tenant ${tenantId} ...`);
  await runSqlFile(client, seedFile, {
    '{SCHEMA}': schemaName,
    '{TENANT_ID}': tenantId,
  });
  log(`Seed data inserted for ${tenantId}.`);
}

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------

async function main() {
  const args = process.argv.slice(2);
  const shouldSeed = args.includes('--seed');
  const allTenants = args.includes('--all-tenants');
  const tenantIdx = args.indexOf('--tenant');
  const specificTenantId = tenantIdx >= 0 ? args[tenantIdx + 1] : undefined;

  const client = await createClient();

  try {
    // 1. Always run shared schema
    await runSharedSchema(client);

    // 2. Determine which tenants to migrate
    let tenantIds: string[] = [];

    if (specificTenantId) {
      tenantIds = [specificTenantId];
    } else if (allTenants) {
      tenantIds = await getAllTenantIds(client);
      if (tenantIds.length === 0) {
        log('No tenants found in it0_shared.tenants. Creating demo tenant...');
        await client.query(`
          INSERT INTO it0_shared.tenants (id, name, slug, plan, owner_user_id, status)
          VALUES ('t001', 'Demo Company', 'demo', 'pro', '00000000-0000-0000-0000-000000000001', 'active')
          ON CONFLICT (id) DO NOTHING
        `);
        tenantIds = ['t001'];
      }
    } else {
      // Default: create/migrate demo tenant
      log('No tenant specified, using demo tenant t001.');
      await client.query(`
        INSERT INTO it0_shared.tenants (id, name, slug, plan, owner_user_id, status)
        VALUES ('t001', 'Demo Company', 'demo', 'pro', '00000000-0000-0000-0000-000000000001', 'active')
        ON CONFLICT (id) DO NOTHING
      `);
      tenantIds = ['t001'];
    }

    // 3. Run tenant migrations
    for (const tid of tenantIds) {
      await runTenantSchema(client, tid);
    }

    // 4. Seed if requested
    if (shouldSeed) {
      for (const tid of tenantIds) {
        await runSeed(client, tid);
      }
    }

    log('All migrations completed successfully.');
  } catch (err) {
    console.error('Migration failed:', err);
    process.exit(1);
  } finally {
    await client.end();
  }
}

main();
