import { ok, type CommandContext } from "@tailor-platform/erp-kit/core";
import type { Transaction } from "../generated/kysely-tailordb";

export type MarkAllNotificationsAsReadInput = Record<string, never>;

/**
 * Adds READ (and SEEN) to every caller-owned, deliverable IN_APP Notification, stamping readAt and writing one audit row per transition. Idempotent.
 */
export async function run(
  db: Transaction,
  _input: MarkAllNotificationsAsReadInput,
  ctx: CommandContext,
) {
  // Select caller-owned, deliverable IN_APP rows. The command is the bulk
  // counterpart of the inbox feed, so it scopes to the IN_APP channel the
  // same way listInboxNotifications / unreadCount do — rows dispatched on
  // other channels (e.g. EMAIL) must not be stamped READ. Engagement-set
  // predicates (READ ∉, ARCHIVED ∉) are filtered post-fetch in JS rather
  // than expressed in raw SQL — the dataset per call is bounded by the
  // user's own inbox so this is a single SELECT followed by per-row UPDATEs.
  const candidates = await db
    .selectFrom("Notification")
    .innerJoin("NotificationChannel", "NotificationChannel.id", "Notification.channelId")
    .where("NotificationChannel.channelId", "=", "IN_APP")
    .selectAll("Notification")
    .where("recipientUserId", "=", ctx.actorId)
    .where("deliveryStatus", "in", ["SENT", "DELIVERED"])
    .forUpdate()
    .execute();

  const now = new Date();
  let transitionedCount = 0;

  for (const row of candidates) {
    if (row.engagementStatuses.includes("READ")) continue;
    if (row.engagementStatuses.includes("ARCHIVED")) continue;

    const seenAlreadyPresent = row.engagementStatuses.includes("SEEN");
    const nextStatuses = [...row.engagementStatuses];
    if (!seenAlreadyPresent) nextStatuses.push("SEEN");
    nextStatuses.push("READ");

    await db
      .updateTable("Notification")
      .set({
        engagementStatuses: nextStatuses,
        seenAt: seenAlreadyPresent ? row.seenAt : now,
        readAt: now,
        updatedAt: now,
      })
      .where("id", "=", row.id)
      .execute();

    await db
      .insertInto("NotificationDeliveryAudit")
      .values({
        id: crypto.randomUUID(),
        notificationId: row.id,
        eventType: "READ",
        occurredAt: now,
        occurredBy: ctx.actorId ?? null,
        errorClass: null,
        errorDetail: null,
        createdAt: now,
        updatedAt: now,
      })
      .execute();

    transitionedCount++;
  }

  return ok({ transitionedCount });
}
