/**
 * Admin outbox resource — read-only queries.
 *
 * - listOutboxEvents: paginated outbox list with status filter.
 *   Status "abandoned" is derived: deadAt IS NOT NULL and no processedAt.
 *
 * No raw SQL. Drizzle ORM only.
 */

import { isNull, isNotNull, and, count } from 'drizzle-orm';
import type { DrizzleClient } from '@/server/db/client.js';
import { outbox } from '@/server/db/schema.js';
import { redactErrorForClient } from '@/server/observability/redact-error.js';
import type { ListOutboxEventsFilter, OutboxEventRow, OutboxStatusFilter } from './types.js';

// ─── listOutboxEvents ─────────────────────────────────────────────────────────

export async function listOutboxEvents(
  db: DrizzleClient,
  filter: ListOutboxEventsFilter,
): Promise<{ data: OutboxEventRow[]; total: number }> {
  // Build where clause based on status filter
  let whereClause;

  if (filter.status === 'pending') {
    // Not yet processed, not failed
    whereClause = and(isNull(outbox.processedAt), isNull(outbox.failedAt));
  } else if (filter.status === 'processed') {
    whereClause = isNotNull(outbox.processedAt);
  } else if (filter.status === 'failed') {
    // Failed but still retryable (not dead) and not processed
    whereClause = and(
      isNotNull(outbox.failedAt),
      isNull(outbox.deadAt),
      isNull(outbox.processedAt),
    );
  } else if (filter.status === 'abandoned') {
    // dead_at IS NOT NULL, not processed
    whereClause = and(isNotNull(outbox.deadAt), isNull(outbox.processedAt));
  }
  // No filter → all events

  const [rows, [countRow]] = await Promise.all([
    db
      .select({
        id: outbox.id,
        aggregateType: outbox.aggregateType,
        aggregateId: outbox.aggregateId,
        eventType: outbox.eventType,
        retryCount: outbox.retryCount,
        lastError: outbox.lastError,
        createdAt: outbox.createdAt,
        processedAt: outbox.processedAt,
        failedAt: outbox.failedAt,
        deadAt: outbox.deadAt,
      })
      .from(outbox)
      .where(whereClause)
      .orderBy(outbox.createdAt)
      .limit(filter.limit)
      .offset(filter.offset),
    db.select({ count: count() }).from(outbox).where(whereClause),
  ]);

  const data: OutboxEventRow[] = rows.map((row) => ({
    id: row.id,
    aggregateType: row.aggregateType,
    aggregateId: row.aggregateId as string,
    eventType: row.eventType,
    retryCount: row.retryCount,
    lastError: redactErrorForClient(row.lastError),
    createdAt: row.createdAt.toISOString(),
    processedAt: row.processedAt ? row.processedAt.toISOString() : null,
    failedAt: row.failedAt ? row.failedAt.toISOString() : null,
    status: deriveStatus(row.processedAt, row.failedAt, row.deadAt),
  }));

  return { data, total: countRow?.count ?? 0 };
}

function deriveStatus(
  processedAt: Date | null,
  failedAt: Date | null,
  deadAt: Date | null,
): OutboxStatusFilter {
  if (processedAt) return 'processed';
  if (deadAt) return 'abandoned';
  if (failedAt) return 'failed';
  return 'pending';
}
