import { PrismaClient } from "../../apps/web/prisma/generated/client";

const prisma = new PrismaClient();

const TARGET_PREFIX = process.env.GITHUB_ISSUE_PREFIX || "GitHub Issue:";
const BATCH_SIZE = Math.max(parseInt(process.env.PURGE_BATCH_SIZE || "100", 10), 1);
const args = new Set(process.argv.slice(2));
const isDryRun = args.has("--dry-run");
const forceRun = args.has("--force");

function chunk<T>(items: T[], size: number): T[][] {
  const output: T[][] = [];
  for (let index = 0; index < items.length; index += size) {
    output.push(items.slice(index, index + size));
  }
  return output;
}

function normalizeJudgeCount(value: unknown): number {
  return typeof value === "number" ? value : 0;
}

async function main() {
  if (!isDryRun && !forceRun) {
    console.error(
      "Refuse to run without explicit mode. Use --dry-run 先看影響筆數，或加上 --force 正式刪除。"
    );
    process.exit(1);
  }

  const targetTasks = await prisma.task.findMany({
    where: {
      title: {
        startsWith: TARGET_PREFIX,
      },
    },
    select: { id: true },
  });
  const targetTaskIds = targetTasks.map((task) => task.id);

  if (targetTaskIds.length === 0) {
    console.log(`No task with prefix "${TARGET_PREFIX}" found. done.`);
    return;
  }

  const submissionIdsForAll = (
    await prisma.submission.findMany({
      where: { task_id: { in: targetTaskIds } },
      select: { id: true },
    })
  ).map((row) => row.id);

  const [taskCount, submissionCount, claimCount, judgeCount, ledgerCount, auditCount, scoutDraftEvents] =
    await Promise.all([
      prisma.task.count({ where: { id: { in: targetTaskIds } } }),
      prisma.submission.count({ where: { task_id: { in: targetTaskIds } } }),
      prisma.claim.count({ where: { task_id: { in: targetTaskIds } } }),
      submissionIdsForAll.length
        ? prisma.judgeResult.count({ where: { submission_id: { in: submissionIdsForAll } } })
        : Promise.resolve(0),
      prisma.ledgerEntry.count({ where: { task_id: { in: targetTaskIds } } }),
      prisma.auditEvent.count({ where: { entityType: "TASK", entityId: { in: targetTaskIds } } }),
      prisma.auditEvent.count({ where: { action: { startsWith: "SCOUT_DRAFT_" } } }),
    ]);

  console.log("=== Purge Impact Preview ===");
  console.log(`Task count: ${normalizeJudgeCount(taskCount)}`);
  console.log(`Submission count: ${normalizeJudgeCount(submissionCount)}`);
  console.log(`Claim count: ${normalizeJudgeCount(claimCount)}`);
  console.log(`JudgeResult count: ${normalizeJudgeCount(judgeCount)}`);
  console.log(`LedgerEntry count: ${normalizeJudgeCount(ledgerCount)}`);
  console.log(`AuditEvent (entityType TASK) count: ${normalizeJudgeCount(auditCount)}`);
  console.log(`AuditEvent (SCOUT_DRAFT_*) count: ${normalizeJudgeCount(scoutDraftEvents)}`);
  console.log(`Target batch size: ${BATCH_SIZE}`);

  if (isDryRun) {
    console.log("Dry-run complete. No data was modified.");
    return;
  }

  for (const idBatch of chunk(targetTaskIds, BATCH_SIZE)) {
    await prisma.$transaction(async (tx) => {
      const batchSubmissionIds = (
        await tx.submission.findMany({
          where: { task_id: { in: idBatch } },
          select: { id: true },
        })
      ).map((row) => row.id);

      if (batchSubmissionIds.length > 0) {
        await tx.judgeResult.deleteMany({
          where: { submission_id: { in: batchSubmissionIds } },
        });
      }

      await tx.submission.deleteMany({
        where: { task_id: { in: idBatch } },
      });
      await tx.claim.deleteMany({
        where: { task_id: { in: idBatch } },
      });
      await tx.ledgerEntry.deleteMany({
        where: { task_id: { in: idBatch } },
      });
      await tx.auditEvent.deleteMany({
        where: {
          OR: [
            {
              entityType: "TASK",
              entityId: { in: idBatch },
            },
            {
              action: { startsWith: "SCOUT_DRAFT_" },
              entityId: { in: idBatch },
            },
          ],
        },
      });
      await tx.task.deleteMany({
        where: { id: { in: idBatch } },
      });
    });
  }

  console.log(`Deleted ${taskCount} GitHub Issue task entries.`);
}

main()
  .catch((error) => {
    console.error("Purge script failed:", error);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });

