#!/usr/bin/env node

import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

const ONE_MINUTE_MS = 60_000;
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
const now = new Date();
const consumedRetentionHours = getPositiveNumber(process.env.AUTH_TOKEN_CONSUMED_RETENTION_HOURS, 24);
const staleLockMinutes = getPositiveNumber(process.env.CAMPAIGN_RETRY_STALE_LOCK_MINUTES, 120);
const webhookRetentionDays = getPositiveNumber(process.env.WEBHOOK_EVENT_RETENTION_DAYS, 30);
const auditRetentionDays = getPositiveNumber(process.env.AUDIT_LOG_RETENTION_DAYS, 365);

function getPositiveNumber(raw, fallback) {
  const parsed = Number(raw);
  if (!Number.isFinite(parsed) || parsed <= 0) {
    return fallback;
  }
  return parsed;
}

function printLine(message) {
  console.log(`[ops-maintenance] ${message}`);
}

async function main() {
  try {
    const consumedCutoff = new Date(now.getTime() - consumedRetentionHours * 60 * 60 * 1000);
    const staleLockCutoff = new Date(now.getTime() - staleLockMinutes * ONE_MINUTE_MS);
    const webhookCutoff = new Date(now.getTime() - webhookRetentionDays * ONE_DAY_MS);
    const auditCutoff = new Date(now.getTime() - auditRetentionDays * ONE_DAY_MS);

    const expiredTokens = await prisma.authToken.deleteMany({
      where: {
        expiresAt: { lte: now },
        consumedAt: null
      }
    });

    const consumedTokens = await prisma.authToken.deleteMany({
      where: {
        consumedAt: { lte: consumedCutoff }
      }
    });

    const recoveredLock = await prisma.backgroundJobState.updateMany({
      where: {
        lockedUntil: { lte: staleLockCutoff },
        lastRunStatus: "running"
      },
      data: {
        lockedUntil: null,
        lastRunStatus: "stale",
        lastError: "Recovered stale lock from maintenance cleanup",
        lastFailureAt: now,
        lastRunCompletedAt: now,
        consecutiveFailures: { increment: 1 }
      }
    });

    const removedWebhookEvents = await prisma.webhookEvent.deleteMany({
      where: {
        createdAt: { lte: webhookCutoff },
        processStatus: { not: "skipped" }
      }
    });

    const removedAuditLogs = await prisma.auditLog.deleteMany({
      where: {
        createdAt: { lte: auditCutoff }
      }
    });

    printLine(`Expired auth tokens deleted: ${expiredTokens.count}`);
    printLine(`Consumed auth tokens deleted (older than ${consumedRetentionHours}h): ${consumedTokens.count}`);
    printLine(`Recovered stale background locks: ${recoveredLock.count}`);
    printLine(`Webhook events deleted (older than ${webhookRetentionDays}d): ${removedWebhookEvents.count}`);
    printLine(`Audit logs deleted (older than ${auditRetentionDays}d): ${removedAuditLogs.count}`);

    const sampleTenant = await prisma.tenant.findFirst({ select: { id: true } });
    const shouldWriteAudit = Boolean(sampleTenant) && (
      expiredTokens.count > 0 ||
      consumedTokens.count > 0 ||
      recoveredLock.count > 0
    );

    if (shouldWriteAudit) {
      const tenantId = sampleTenant.id;
      await prisma.auditLog.create({
        data: {
          tenantId,
          actorUserId: null,
          entityType: "system",
          entityId: "maintenance",
          action: "ops_maintenance_cleanup",
          metadataJson: JSON.stringify({
            expiredAuthTokens: expiredTokens.count,
            consumedAuthTokens: consumedTokens.count,
            recoveredLocks: recoveredLock.count,
            webhookEventsDeleted: removedWebhookEvents.count,
            auditLogsDeleted: removedAuditLogs.count,
            consumedRetentionHours,
            staleLockMinutes,
            webhookRetentionDays,
            auditRetentionDays
          })
        }
      });
    }

    printLine("maintenance completed");
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error);
    console.error(`[ops-maintenance] failed: ${message}`);
    process.exitCode = 1;
  } finally {
    await prisma.$disconnect();
  }
}

await main();
