import { createDbService } from '@/server/services/db.js';
import { sql } from 'drizzle-orm';
import type { AlertSeverity } from '@/server/cron/settlement-monitor.js';
import { redactError } from '../redact.js';
import type { CheckAdapter, CheckContext, CheckResult } from '../types.js';

export interface WebhookStaleMetrics {
  staleCount: number;
  oldestStaleMinutes: number;
}
export interface WebhookStaleConfig {
  staleMinutes: number;
}

export function evaluateWebhookStale(
  m: WebhookStaleMetrics,
  cfg: WebhookStaleConfig,
): { severity: AlertSeverity; detail: string } {
  if (m.staleCount > 0 && m.oldestStaleMinutes >= cfg.staleMinutes) {
    return {
      severity: 'page',
      detail: `${m.staleCount} webhook event(s) claimed but unprocessed; oldest ${m.oldestStaleMinutes}m (>= ${cfg.staleMinutes}m)`,
    };
  }
  return {
    severity: 'info',
    detail:
      m.staleCount > 0
        ? `${m.staleCount} in-flight (<${cfg.staleMinutes}m)`
        : 'no stale webhook events',
  };
}

export const webhookIdempotencyStale: CheckAdapter = {
  key: 'webhook_idempotency_stale',
  title: 'Stripe webhook idempotency stalls',
  defaultConfig: { staleMinutes: 10 },
  defaultIntervalHours: 1,
  async run(ctx: CheckContext): Promise<CheckResult> {
    const cfg = { staleMinutes: Number(ctx.config.staleMinutes ?? 10) };
    try {
      const db = createDbService({ DATABASE_URL: ctx.env.DATABASE_URL });
      const res = await db.execute<{ n: number; oldest: string | null }>(sql`
        SELECT count(*)::int AS n, MIN(claimed_at) AS oldest
        FROM stripe_webhook_events
        WHERE processed_at IS NULL AND claimed_at IS NOT NULL
      `);
      const row = res.rows[0];
      const oldest = row?.oldest ? new Date(row.oldest) : null;
      const oldestStaleMinutes = oldest
        ? Math.floor((ctx.now.getTime() - oldest.getTime()) / 60_000)
        : 0;
      const m: WebhookStaleMetrics = { staleCount: row?.n ?? 0, oldestStaleMinutes };
      const ev = evaluateWebhookStale(m, cfg);
      return {
        key: this.key,
        severity: ev.severity,
        title: this.title,
        detail: ev.detail,
        metrics: { staleCount: m.staleCount, oldestStaleMinutes },
      };
    } catch (err) {
      return {
        key: this.key,
        severity: 'warn',
        degraded: true,
        title: this.title,
        detail: redactError(err, 'check threw'),
      };
    }
  },
};
