/**
 * Axis-B inventory migration from host deal_skus + stock_reservations.
 * Run: npx tsx apps/web/src/server/stock/inventory-migration.ts
 *
 * Idempotent — all INSERTs use ON CONFLICT DO NOTHING.
 */
import { scriptOutput } from '../lib/script-output.js';
import { pathToFileURL } from 'node:url';
import { drizzle } from 'drizzle-orm/neon-serverless';
import { Pool, neonConfig } from '@neondatabase/serverless';
import { and, eq, gt, isNotNull, isNull, sql } from 'drizzle-orm';
import ws from 'ws';
import { inventoryItem } from '@platform-modules/commerce-inventory';
import type { DrizzleDb } from '@/server/db/client.js';
import { dealSkus, deals, stockReservations } from '@/server/db/schema.js';
import { composedSchema } from '../db/schema-composed.js';
import { pushSchema, toInventoryDb } from './inventory-platform.js';
import {
  seedActiveReservations,
  seedInventoryItems,
} from '@/server/db/queries/stock/inventory-migration.js';

export async function runInventoryMigration(
  db: DrizzleDb,
): Promise<{ seeded: number; reservations: number }> {
  await pushSchema(toInventoryDb(db));

  const skuRows = await db
    .select({
      id: dealSkus.id,
      quantityTotal: dealSkus.quantityTotal,
      quantitySold: dealSkus.quantitySold,
      vendorId: deals.vendorId,
    })
    .from(dealSkus)
    .innerJoin(deals, eq(dealSkus.dealId, deals.id));

  if (skuRows.length === 0) {
    throw new Error('inventory-migration: no deal_skus found — unexpected');
  }

  const seeded = await seedInventoryItems(db, skuRows);

  const activeHostReservations = await db
    .select({
      id: stockReservations.id,
      skuId: stockReservations.skuId,
      qty: stockReservations.qty,
      paymentIntentId: stockReservations.paymentIntentId,
      expiresAt: stockReservations.expiresAt,
    })
    .from(stockReservations)
    .where(
      and(
        isNull(stockReservations.consumedAt),
        isNull(stockReservations.releasedAt),
        gt(stockReservations.expiresAt, sql`now()`),
        isNotNull(stockReservations.paymentIntentId),
      ),
    );

  const reservations = await seedActiveReservations(
    db,
    activeHostReservations.map((row) => ({
      id: row.id,
      skuId: row.skuId,
      qty: row.qty,
      paymentIntentId: row.paymentIntentId!,
      expiresAt: row.expiresAt,
    })),
  );

  const countResult = await db.select({ total: sql<number>`count(*)::int` }).from(inventoryItem);
  const total = countResult[0]?.total ?? 0;

  if (total < seeded) {
    throw new Error(`inventory-migration: inventory_item count (${total}) < seeded (${seeded})`);
  }

  if (seeded === 0 && total === 0) {
    throw new Error('inventory-migration: seeded 0 inventory items — unexpected');
  }

  scriptOutput(
    `inventory-migration: seeded ${seeded} inventory items, ${reservations} active reservations`,
  );

  return { seeded, reservations };
}

async function main() {
  const DATABASE_URL = process.env['DATABASE_URL'];
  if (!DATABASE_URL) throw new Error('DATABASE_URL env var required');

  neonConfig.webSocketConstructor = ws;
  const pool = new Pool({ connectionString: DATABASE_URL });
  const schema = composedSchema;
  const db = drizzle(pool, { schema }) as DrizzleDb;

  try {
    await runInventoryMigration(db);
  } finally {
    await pool.end();
  }
}

if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
  main()
    .then(() => process.exit(0))
    .catch((err) => {
      console.error('inventory-migration failed:', err);
      process.exit(1);
    });
}
