import {
  ok,
  err,
  type ReadonlyDB,
  type QueryContext,
  type PaginationInput,
  buildPaginatedResult,
  DEFAULT_PAGE_SIZE,
} from "@tailor-platform/erp-kit/core";
import type { DB } from "../generated/kysely-tailordb";
import { ForbiddenError } from "../lib/errors.generated";

type AuditEventType =
  | "QUEUED"
  | "SENT"
  | "DELIVERED"
  | "SEEN"
  | "READ"
  | "ARCHIVED"
  | "FAILED"
  | "BOUNCED"
  | "OPENED";

type AuditOrderByField = "occurredAt" | "createdAt";

export interface SearchNotificationDeliveryAuditInput extends PaginationInput<AuditOrderByField> {
  eventType?: AuditEventType;
  dateRange?: {
    from?: string;
    to?: string;
  };
  recipientUserId?: string;
  sourceType?: string;
  sourceId?: string;
  from?: string;
  to?: string;
}

/**
 * Searches the delivery-audit trail with optional filters ordered by occurredAt desc; callers are scoped to their own rows.
 */
export async function run(
  db: ReadonlyDB<DB>,
  input: SearchNotificationDeliveryAuditInput,
  ctx: QueryContext,
) {
  const limit = input.limit ?? DEFAULT_PAGE_SIZE;
  const offset = input.offset ?? 0;
  const orderBy = input.orderBy ?? "occurredAt";
  const orderDirection = input.orderDirection ?? "desc";

  // Self-scope: an explicit recipientUserId filter must match the caller;
  // results are always restricted to the caller's own audit rows.
  if (input.recipientUserId !== undefined && input.recipientUserId !== ctx.actorId) {
    return err(new ForbiddenError(input.recipientUserId));
  }

  // Audit rows are anchored to a parent Notification. Resolve the caller's
  // matching notificationIds first, applying the optional source filters.
  let parentQuery = db
    .selectFrom("Notification")
    .select(["id"])
    .where("recipientUserId", "=", ctx.actorId);

  if (input.sourceType !== undefined) {
    parentQuery = parentQuery.where("sourceType", "=", input.sourceType);
  }
  if (input.sourceId !== undefined) {
    parentQuery = parentQuery.where("sourceId", "=", input.sourceId);
  }

  const parents = await parentQuery.execute();
  const notificationIdFilter = parents.map((p) => p.id);

  if (notificationIdFilter.length === 0) {
    return ok(buildPaginatedResult([], limit));
  }

  let query = db.selectFrom("NotificationDeliveryAudit").selectAll();

  if (input.eventType !== undefined) {
    query = query.where("eventType", "=", input.eventType);
  }
  const from = input.dateRange?.from ?? input.from;
  const to = input.dateRange?.to ?? input.to;
  if (from !== undefined) {
    query = query.where("occurredAt", ">=", new Date(from));
  }
  if (to !== undefined) {
    query = query.where("occurredAt", "<=", new Date(to));
  }
  query = query.where("notificationId", "in", notificationIdFilter);

  const rows = await query
    .orderBy(orderBy, orderDirection)
    .limit(limit + 1)
    .offset(offset)
    .execute();

  return ok(buildPaginatedResult(rows, limit));
}
