/**
 * Seed 5 customer test users with purchase history against real live deals.
 * Run: DATABASE_URL=... PII_KEY=... tsx src/server/db/seeds/seed-customer-users.ts
 *
 * Appends credentials to Docs/logins.dev
 */

import { scriptOutput } from '../../lib/script-output.js';
import { bytesToHex } from '@/lib/encoding.js';
import { eq } from 'drizzle-orm';
import * as schema from '../schema.js';
import { getDb } from '../client.js';
import { blindIndex } from '../crypto.js';
import { setUserEmail } from '../pii-write.js';
import { hashPassword } from '../../auth/credentials.js';
import { appendFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { createUserRecord, incrementPurchaseCountBy } from '../queries/users.js';
import { insertSeedVoucherPurchase } from '../queries/seed-orders.js';
import { readSeedCliEnv } from '../seed-cli-env.js';

const { DATABASE_URL, PII_KEY, PASSWORD_PEPPER_V1 } = readSeedCliEnv();

const piiKey = PII_KEY as string;
const db = getDb({ DATABASE_URL });

// ── PRNG (mulberry32) ─────────────────────────────────────────────────────────

function mulberry32(seed: number) {
  return function () {
    let t = (seed += 0x6d2b79f5);
    t = Math.imul(t ^ (t >>> 15), t | 1);
    t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

const rng = mulberry32(0xdeadbeef);

function randInt(min: number, max: number) {
  return Math.floor(rng() * (max - min + 1)) + min;
}

function randomHex(bytes: number): string {
  const view = new Uint8Array(bytes);
  crypto.getRandomValues(view);
  return bytesToHex(view);
}

// ── Display names ─────────────────────────────────────────────────────────────

const NAMES = ['יעל דוידוב', 'אבי שרון', 'רחל מנחם', 'נועם בר-לב', 'תהילה אזולאי'];

const PASSWORD = 'Multideal1!';

async function main() {
  scriptOutput('Fetching live deals…');
  const liveDeals = await db
    .select({
      id: schema.deals.id,
      vendorId: schema.deals.vendorId,
      discountedPrice: schema.deals.minPrice,
      commissionRate: schema.deals.commissionRate,
      skuId: schema.dealSkus.id,
    })
    .from(schema.deals)
    .innerJoin(schema.dealSkus, eq(schema.dealSkus.dealId, schema.deals.id))
    .where(eq(schema.deals.dealState, 'ACTIVE'))
    .limit(40);

  if (liveDeals.length === 0) throw new Error('No ACTIVE deals found — seed vendors/deals first');
  scriptOutput(`Found ${liveDeals.length} active deals`);

  const passwordHash = await hashPassword(PASSWORD, PASSWORD_PEPPER_V1);
  const logins: string[] = [];

  for (let i = 0; i < 5; i++) {
    const num = String(i + 1).padStart(2, '0');
    const rawEmail = `customer${num}@multi.deal`;
    const displayName = NAMES[i]!;

    const emailIdx = await blindIndex(rawEmail, piiKey);

    // Skip if already exists
    const existing = await db
      .select({ id: schema.users.id })
      .from(schema.users)
      .where(eq(schema.users.emailIndex, emailIdx))
      .limit(1);

    let userId: string;

    if (existing.length > 0) {
      userId = existing[0]!.id;
      scriptOutput(`  [${num}] ${rawEmail} already exists (${userId}) — skipping user insert`);
    } else {
      const emailPatch = await setUserEmail(rawEmail, piiKey);
      const user = await createUserRecord(db, {
        ...emailPatch,
        passwordHash,
        avatarType: 'ICON',
        avatarValue: `icon_${randInt(1, 12)}`,
        purchaseCount: 0,
        accountState: 'ACTIVE',
        isAdmin: false,
      });
      userId = user.id;
      scriptOutput(`  [${num}] Created ${rawEmail} → ${userId}`);
    }

    // 2–4 purchases per user against random live deals
    const purchaseCount = randInt(2, 4);
    const shuffled = [...liveDeals].sort(() => rng() - 0.5);
    const selectedDeals = shuffled.slice(0, Math.min(purchaseCount, shuffled.length));

    let insertedPurchases = 0;
    for (const deal of selectedDeals) {
      const amount = Number(deal.discountedPrice);

      // Mix of statuses for realistic history
      const statusRoll = rng();
      const paymentStatus = statusRoll < 0.85 ? 'COMPLETED' : 'PENDING';
      const redemptionRoll = rng();
      const redemptionStatus =
        paymentStatus === 'COMPLETED'
          ? redemptionRoll < 0.4
            ? 'REDEEMED'
            : 'UNREDEEMED'
          : 'UNREDEEMED';

      const redeemedAt =
        redemptionStatus === 'REDEEMED'
          ? new Date(Date.now() - randInt(1, 30) * 24 * 60 * 60 * 1000)
          : null;

      const expiresAt = new Date(Date.now() + 180 * 24 * 60 * 60 * 1000);
      const qrTokenHash = randomHex(32);
      const idempotencyKey = `seed-customer-${userId}-${deal.id}`;

      // Skip duplicate idempotency keys (re-run safety)
      const existingOrder = await db
        .select({ id: schema.order.id })
        .from(schema.order)
        .where(eq(schema.order.idempotencyKey, idempotencyKey))
        .limit(1);

      if (existingOrder.length > 0) {
        scriptOutput(`    Purchase for deal ${deal.id} already exists — skip`);
        continue;
      }

      const amountAgorot = BigInt(Math.round(amount * 100));
      const orderCreatedAt = new Date(Date.now() - randInt(1, 60) * 24 * 60 * 60 * 1000);

      const voucherId = crypto.randomUUID();
      await insertSeedVoucherPurchase(db, {
        buyerUserId: userId,
        vendorId: deal.vendorId,
        variantId: deal.skuId,
        amountAgorot,
        idempotencyKey,
        requestHash: `seed-${idempotencyKey}`,
        orderStatus: paymentStatus === 'COMPLETED' ? 'paid' : 'pending',
        orderCreatedAt,
        voucherId,
        redemptionStatus,
        expiresAt,
        redeemedAt: redeemedAt ?? null,
        qrTokenHash,
        reviewEligible: redemptionStatus === 'REDEEMED',
      });

      if (paymentStatus === 'COMPLETED') insertedPurchases++;
    }

    // Update purchaseCount to reflect completed purchases
    if (insertedPurchases > 0) {
      await incrementPurchaseCountBy(db, userId, insertedPurchases);
    }

    logins.push(
      `\nUser     │ ${displayName}\nEmail    │ ${rawEmail}\nPassword │ ${PASSWORD}\nUser ID  │ ${userId}\nLogin    │ https://dev.multi.deal/login → email + password tab`,
    );
  }

  // Append to Docs/logins.dev
  const loginsPath = resolve(process.cwd(), '../../Docs/logins.dev');
  const separator =
    '\n\n# ── Customer test users (seeded by seed-customer-users.ts) ─────────────────\n# Email login verified pattern. Password: Multideal1! for all.\n';
  appendFileSync(loginsPath, separator + logins.join('\n'));
  scriptOutput(`\nAppended ${logins.length} credentials to Docs/logins.dev`);
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});
