/**
 * Backfill Setup Fee Paid Flag
 *
 * Purpose: Set setupFeePaid = true for existing users who have already paid
 * the setup fee before this flag was tracked.
 *
 * Logic:
 * - Find all users with existing subscriptions (any status)
 * - Set setupFeePaid = true for their first/earliest subscription
 * - Set setupFeePaidAt to the createdAt date of that subscription
 *
 * Safety:
 * - Dry run mode by default (set DRY_RUN=false to actually update)
 * - Logs all changes before applying
 * - Uses transactions for safety
 *
 * Usage:
 *   # Dry run (no changes)
 *   npx ts-node scripts/backfill-setup-fee-paid.ts
 *
 *   # Actually apply changes
 *   DRY_RUN=false npx ts-node scripts/backfill-setup-fee-paid.ts
 */

import { prisma } from '../lib/db';

const DRY_RUN = process.env.DRY_RUN !== 'false';

interface BackfillResult {
  userId: string;
  userEmail: string;
  subscriptionId: string;
  setupFeePaidAt: Date;
  hadStripCustomerId: boolean;
}

async function backfillSetupFeePaid() {
  console.log('🚀 Starting Setup Fee Backfill Script');
  console.log(`📝 Mode: ${DRY_RUN ? 'DRY RUN (no changes will be made)' : 'LIVE (changes will be applied)'}\n`);

  try {
    // Step 1: Find all users who have subscriptions but setupFeePaid is false
    const usersWithSubscriptions = await prisma.subscriptions.groupBy({
      by: ['userId'],
      where: {
        setupFeePaid: false,
      },
      _count: {
        userId: true,
      },
    });

    console.log(`📊 Found ${usersWithSubscriptions.length} users with unpaid setup fee flags\n`);

    if (usersWithSubscriptions.length === 0) {
      console.log('✅ No users need backfilling. All done!');
      return;
    }

    const results: BackfillResult[] = [];

    // Step 2: For each user, find their earliest subscription
    for (const { userId } of usersWithSubscriptions) {
      // Get user details
      const user = await prisma.users.findUnique({
        where: { id: userId },
        select: {
          id: true,
          email: true,
          stripeCustomerId: true,
        },
      });

      if (!user) {
        console.log(`⚠️  User ${userId} not found, skipping...`);
        continue;
      }

      // Find the earliest subscription for this user
      const earliestSubscription = await prisma.subscriptions.findFirst({
        where: { userId },
        orderBy: { createdAt: 'asc' },
        select: {
          id: true,
          createdAt: true,
          setupFeePaid: true,
        },
      });

      if (!earliestSubscription) {
        console.log(`⚠️  No subscription found for user ${user.email}, skipping...`);
        continue;
      }

      // If setup fee is already marked as paid, skip
      if (earliestSubscription.setupFeePaid) {
        console.log(`✓  User ${user.email} already has setupFeePaid = true, skipping...`);
        continue;
      }

      // Mark this subscription as having paid the setup fee
      results.push({
        userId: user.id,
        userEmail: user.email,
        subscriptionId: earliestSubscription.id,
        setupFeePaidAt: earliestSubscription.createdAt,
        hadStripCustomerId: !!user.stripeCustomerId,
      });
    }

    // Step 3: Display what will be changed
    console.log('📋 Subscriptions to update:\n');
    console.log('┌─────────────────────────────────────┬─────────────────────────┬──────────────────────┬─────────────────┐');
    console.log('│ User Email                          │ Subscription ID         │ Setup Fee Paid At    │ Had Stripe ID   │');
    console.log('├─────────────────────────────────────┼─────────────────────────┼──────────────────────┼─────────────────┤');

    results.forEach(({ userEmail, subscriptionId, setupFeePaidAt, hadStripCustomerId }) => {
      const email = userEmail.padEnd(35).substring(0, 35);
      const subId = subscriptionId.substring(0, 23).padEnd(23);
      const date = setupFeePaidAt.toISOString().substring(0, 19).padEnd(20);
      const stripeId = (hadStripCustomerId ? 'Yes' : 'No').padEnd(15);
      console.log(`│ ${email} │ ${subId} │ ${date} │ ${stripeId} │`);
    });

    console.log('└─────────────────────────────────────┴─────────────────────────┴──────────────────────┴─────────────────┘');
    console.log(`\n📊 Total subscriptions to update: ${results.length}\n`);

    // Step 4: Apply changes (if not dry run)
    if (!DRY_RUN) {
      console.log('💾 Applying changes...\n');

      let successCount = 0;
      let errorCount = 0;

      for (const { subscriptionId, setupFeePaidAt } of results) {
        try {
          await prisma.subscriptions.update({
            where: { id: subscriptionId },
            data: {
              setupFeePaid: true,
              setupFeePaidAt: setupFeePaidAt,
            },
          });
          successCount++;
          process.stdout.write('.');
        } catch (error) {
          console.error(`\n❌ Error updating subscription ${subscriptionId}:`, error);
          errorCount++;
        }
      }

      console.log(`\n\n✅ Successfully updated ${successCount} subscriptions`);
      if (errorCount > 0) {
        console.log(`❌ Failed to update ${errorCount} subscriptions`);
      }
    } else {
      console.log('⚠️  DRY RUN MODE - No changes were made');
      console.log('   Run with DRY_RUN=false to apply changes\n');
    }

  } catch (error) {
    console.error('❌ Error during backfill:', error);
    throw error;
  } finally {
    await prisma.$disconnect();
  }
}

// Run the script
backfillSetupFeePaid()
  .then(() => {
    console.log('\n🎉 Backfill script completed successfully!');
    process.exit(0);
  })
  .catch((error) => {
    console.error('\n💥 Backfill script failed:', error);
    process.exit(1);
  });
