const MAX_EVENTS = 50;
const MAX_PREVIEW_LENGTH = 240;

export interface SlowRequestEvent {
  id: string;
  method: string;
  path: string;
  durationMs: number;
  thresholdMs: number;
  occurredAt: string;
}

export interface SlowPrismaQueryEvent {
  id: string;
  queryPreview: string;
  durationMs: number;
  thresholdMs: number;
  occurredAt: string;
}

export interface OpsRuntimeEvents {
  slowRequests: SlowRequestEvent[];
  slowQueries: SlowPrismaQueryEvent[];
}

interface RecordSlowRequestInput {
  method: string;
  url: string;
  durationMs: number;
  thresholdMs: number;
  occurredAt?: Date;
}

interface RecordSlowPrismaQueryInput {
  query: string;
  durationMs: number;
  thresholdMs: number;
  occurredAt?: Date;
}

const slowRequests: SlowRequestEvent[] = [];
const slowQueries: SlowPrismaQueryEvent[] = [];
let nextId = 1;

export function recordSlowRequest(input: RecordSlowRequestInput) {
  slowRequests.unshift({
    id: makeId('req'),
    method: normalizeMethod(input.method),
    path: sanitizeRequestPath(input.url),
    durationMs: Math.round(input.durationMs),
    thresholdMs: Math.round(input.thresholdMs),
    occurredAt: (input.occurredAt ?? new Date()).toISOString(),
  });
  trim(slowRequests);
}

export function recordSlowPrismaQuery(input: RecordSlowPrismaQueryInput) {
  slowQueries.unshift({
    id: makeId('qry'),
    queryPreview: truncate(redactText(input.query.replace(/\s+/g, ' ').trim()), MAX_PREVIEW_LENGTH),
    durationMs: Math.round(input.durationMs),
    thresholdMs: Math.round(input.thresholdMs),
    occurredAt: (input.occurredAt ?? new Date()).toISOString(),
  });
  trim(slowQueries);
}

export function getOpsRuntimeEvents(): OpsRuntimeEvents {
  return {
    slowRequests: slowRequests.map((event) => ({ ...event })),
    slowQueries: slowQueries.map((event) => ({ ...event })),
  };
}

export function clearOpsRuntimeEventsForTests() {
  slowRequests.splice(0, slowRequests.length);
  slowQueries.splice(0, slowQueries.length);
  nextId = 1;
}

export function redactText(value: string, maxLength = 500): string {
  const redacted = value
    .replace(/(^|[^A-Za-z0-9])sk-[A-Za-z0-9_-]+/g, '$1[redacted]')
    .replace(/(api[_-]?key|token|secret|password|authorization)(\s*[=:]\s*)(["']?)[^&\s"']+/gi, '$1$2$3[redacted]');
  return truncate(redacted, maxLength);
}

function sanitizeRequestPath(url: string): string {
  const raw = String(url || 'unknown-url');
  try {
    const parsed = new URL(raw, 'http://local.invalid');
    return redactText(parsed.pathname || '/');
  } catch {
    return redactText(raw.split('?')[0] || 'unknown-url');
  }
}

function normalizeMethod(method: string): string {
  const value = String(method || 'UNKNOWN').toUpperCase();
  return /^[A-Z]+$/.test(value) ? value : 'UNKNOWN';
}

function truncate(value: string, maxLength: number): string {
  if (value.length <= maxLength) return value;
  return `${value.slice(0, Math.max(0, maxLength - 3))}...`;
}

function trim<T>(items: T[]) {
  if (items.length > MAX_EVENTS) items.splice(MAX_EVENTS);
}

function makeId(prefix: string): string {
  const id = `${prefix}-${Date.now().toString(36)}-${nextId.toString(36)}`;
  nextId += 1;
  return id;
}
