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 DepRow {
  dep: string;
  failures: number;
}
export interface DepConfig {
  burstThreshold: number;
  windowMinutes?: number;
}

export function evaluateDepLiveness(
  rows: DepRow[],
  cfg: DepConfig,
): { severity: AlertSeverity; detail: string } {
  const bursts = rows.filter((r) => r.failures >= cfg.burstThreshold);
  if (bursts.length === 0)
    return {
      severity: 'info',
      detail: rows.map((r) => `${r.dep}=${r.failures}`).join(', ') || 'no failures',
    };
  return {
    severity: 'page',
    detail: bursts.map((r) => `${r.dep}: ${r.failures} failures`).join('; '),
  };
}

export const externalDepLiveness: CheckAdapter = {
  key: 'external_dep_liveness',
  title: 'External dependency liveness (derived)',
  defaultConfig: { burstThreshold: 5, windowMinutes: 60 },
  defaultIntervalHours: 1,
  async run(ctx: CheckContext): Promise<CheckResult> {
    const cfg = {
      burstThreshold: Number(ctx.config.burstThreshold ?? 5),
      windowMinutes: Number(ctx.config.windowMinutes ?? 60),
    };
    try {
      const db = createDbService({ DATABASE_URL: ctx.env.DATABASE_URL });
      // Derived signal: recently-failed, not-yet-succeeded outbox dispatches (the internal
      // failure marker that DOES exist on `outbox`: failed_at IS NOT NULL, processed_at IS NULL).
      // No `.catch` swallow — a genuine query/IO error must fall through to the outer catch and
      // surface as warn+degraded (a broken check must never masquerade as healthy info).
      const res = await db.execute<{ failures: number }>(sql`
        SELECT count(*)::int AS failures
        FROM outbox
        WHERE failed_at IS NOT NULL
          AND processed_at IS NULL
          AND failed_at > NOW() - (${cfg.windowMinutes} || ' minutes')::interval
      `);
      const rows: DepRow[] = [{ dep: 'outbox_dispatch', failures: res.rows[0]?.failures ?? 0 }];
      const ev = evaluateDepLiveness(rows, cfg);
      return {
        key: this.key,
        severity: ev.severity,
        title: this.title,
        detail: ev.detail,
        metrics: { outboxFailures: rows[0]!.failures },
      };
    } catch (err) {
      return {
        key: this.key,
        severity: 'warn',
        degraded: true,
        title: this.title,
        detail: redactError(err, 'check threw'),
      };
    }
  },
};
