import dayjs from "dayjs";
import mongoose from "mongoose";
import { MessageRecord } from "../models/messageRecordModel";
import { MessageStatsDailyUid } from "../models/messageStatsDailyUidModel";

const TIMEZONE = "America/Los_Angeles";
const BATCH_SIZE = 2000;
const MONGO_URI = process.env.MONGO_URI || "mongodb://oms:oms123.@localhost:27717/omsdb?authSource=admin";

function parseArg(name: string): string | undefined {
  const idx = process.argv.indexOf(name);
  if (idx === -1) return undefined;
  return process.argv[idx + 1];
}

async function buildForDay(dateKey: string): Promise<number> {
  const start = dayjs(dateKey).startOf("day").toDate();
  const end = dayjs(dateKey).add(1, "day").startOf("day").toDate();

  const pipeline = [
    {
      $match: {
        createdAt: { $gte: start, $lt: end },
      },
    },
    {
      $group: {
        _id: {
          date: { $dateTrunc: { date: "$createdAt", unit: "day", timezone: TIMEZONE } },
          dateKey: { $dateToString: { format: "%Y-%m-%d", date: "$createdAt", timezone: TIMEZONE } },
          strategyId: "$strategyId",
          strategyName: "$strategyName",
          templateName: "$templateName",
          cc: "$cc",
          image: "$image",
          status: "$status",
          inforeground: "$inforeground",
          uid: "$uid",
        },
        msgCount: { $sum: 1 },
      },
    },
  ];

  const cursor = MessageRecord.aggregate(pipeline).allowDiskUse(true).cursor({ batchSize: BATCH_SIZE });

  let processed = 0;
  let ops: any[] = [];

  for await (const row of cursor) {
    const id = row._id || {};
    ops.push({
      updateOne: {
        filter: {
          dateKey: id.dateKey,
          strategyId: id.strategyId || null,
          strategyName: id.strategyName || null,
          templateName: id.templateName || null,
          cc: id.cc || null,
          image: id.image || null,
          status: id.status,
          inforeground: id.inforeground,
          uid: id.uid,
        },
        update: {
          $set: {
            date: id.date,
            dateKey: id.dateKey,
            strategyId: id.strategyId || null,
            strategyName: id.strategyName || null,
            templateName: id.templateName || null,
            cc: id.cc || null,
            image: id.image || null,
            status: id.status,
            inforeground: id.inforeground,
            uid: id.uid,
            msgCount: row.msgCount,
          },
        },
        upsert: true,
      },
    });

    if (ops.length >= BATCH_SIZE) {
      await MessageStatsDailyUid.bulkWrite(ops, { ordered: false });
      processed += ops.length;
      ops = [];
    }
  }

  if (ops.length > 0) {
    await MessageStatsDailyUid.bulkWrite(ops, { ordered: false });
    processed += ops.length;
  }

  return processed;
}

async function main() {
  const startArg = parseArg("--start");
  const endArg = parseArg("--end");

  if (!startArg || !endArg) {
    throw new Error("Usage: npx ts-node src/scripts/backfill-message-stats-preaggregate.ts --start YYYY-MM-DD --end YYYY-MM-DD");
  }

  const start = dayjs(startArg).startOf("day");
  const end = dayjs(endArg).startOf("day");
  if (!start.isValid() || !end.isValid() || end.isBefore(start)) {
    throw new Error("Invalid date range. Expected --start <= --end, format YYYY-MM-DD");
  }

  await mongoose.connect(MONGO_URI);
  console.log(`[MessageStatsPreAgg] connected. range=${start.format("YYYY-MM-DD")}..${end.format("YYYY-MM-DD")}`);

  let cursor = start;
  let total = 0;
  while (!cursor.isAfter(end)) {
    const dateKey = cursor.format("YYYY-MM-DD");
    const startedAt = Date.now();
    const processed = await buildForDay(dateKey);
    total += processed;
    console.log(`[MessageStatsPreAgg] day=${dateKey} processed=${processed} elapsed=${Date.now() - startedAt}ms`);
    cursor = cursor.add(1, "day");
  }

  console.log(`[MessageStatsPreAgg] done. total upsert ops=${total}`);
  await mongoose.disconnect();
}

main().catch((error) => {
  console.error("[MessageStatsPreAgg] fatal", error);
  process.exit(1);
});
