import { prisma } from "@linkwarden/prisma";
import transporter from "@linkwarden/lib/transporter";
import Handlebars from "handlebars";
import { readFileSync } from "fs";
import path from "path";

const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms));

const batchSize = 10;
const pauseMs = 30000;

/**
 * Runs the "trial ended" notifier in batches.
 * - Only runs if NEXT_PUBLIC_TRIAL_PERIOD_DAYS > 1
 * - Picks users whose createdAt is older than that trial window AND trialEndEmailSent=false
 * - Skips users with an active own or parent subscription
 * - Sends email via the provided transporter
 * - Marks trialEndEmailSent=true for processed users (including those with active subs)
 * - Waits for a minute between batches
 */
export async function trialEndEmailWorker() {
  const trialDays = Number(process.env.NEXT_PUBLIC_TRIAL_PERIOD_DAYS);
  if (
    !Number.isFinite(trialDays) ||
    trialDays <= 1 ||
    !process.env.STRIPE_SECRET_KEY ||
    process.env.NEXT_PUBLIC_REQUIRE_CC === "true"
  ) {
    return;
  }

  console.log("\x1b[34m%s\x1b[0m", `Starting trial-ended email worker...`);

  const cutoff = new Date(Date.now() - trialDays * 24 * 60 * 60 * 1000);
  const from = {
    name: "Linkwarden",
    address: String(process.env.EMAIL_FROM),
  };

  while (true) {
    // 1) Pick a batch of candidates
    const candidates = await prisma.user.findMany({
      where: {
        trialEndEmailSent: false,
        emailVerified: {
          not: null,
        },
        createdAt: { lte: cutoff, gte: new Date("2025-09-25") }, // safety upper bound to avoid processing old users
      },
      orderBy: { createdAt: "asc" },
      take: batchSize,
      include: {
        subscriptions: { select: { active: true } }, // own subscription
        parentSubscription: { select: { active: true } }, // family/parent plan
      },
    });

    if (candidates.length === 0) {
      await sleep(pauseMs);
      continue;
    }

    const processedIds: number[] = [];
    let emailsSent = 0;

    // 2) Process the batch (send emails if no active sub)
    for (const user of candidates) {
      const hasActive =
        Boolean(user.subscriptions?.active) ||
        Boolean(user.parentSubscription?.active);

      // We’ll mark users as processed at the end of this loop iteration.
      // If sending fails, we skip marking so we retry next pass.
      if (!hasActive && user.email) {
        emailsSent++;
        try {
          const emailsDir = path.resolve(process.cwd(), "templates");

          const templateFile = readFileSync(
            path.join(emailsDir, "trialEnded.html"),
            "utf8"
          );

          const emailTemplate = Handlebars.compile(templateFile);

          await transporter.sendMail({
            from,
            to: user.email,
            subject: "Your Linkwarden trial has ended",
            html: emailTemplate({
              name: user.name?.trim() ? user.name.trim() : "there",
              url: process.env.BASE_URL,
            }),
          });
        } catch (err) {
          console.error(
            `[trial-worker] Failed to send trial-ended email to user ${user.id}`,
            err
          );
          // Do not mark as processed so it can be retried on the next batch run
          await sleep(pauseMs);
          continue;
        }
      }

      // Whether we emailed or skipped (active sub, or missing email), mark processed
      processedIds.push(user.id);
    }

    // 3) Mark processed users so we don't pick them again
    if (processedIds.length) {
      await prisma.user.updateMany({
        where: { id: { in: processedIds } },
        data: { trialEndEmailSent: true },
      });
      console.log(
        "\x1b[34m%s\x1b[0m",
        `Marked off ${processedIds.length} users' trialEndEmailSent to true. Emails sent: ${emailsSent}`
      );
    }

    // 4) Pause before the next batch
    await sleep(pauseMs);
  }
}
