/**
 * Seed 20 test users with purchase history against real live deals.
 * Run: DATABASE_URL=... PII_KEY=... tsx src/server/db/seeds/seed-test-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(0xc0ffee42);

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 < 20; i++) {
    const num = String(i + 1).padStart(2, '0');
    const rawEmail = `testuser${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-test-${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# ── Test users (seeded by seed-test-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);
});
