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

export interface MarkNotificationsAsSeenInput {}

/**
 * Adds SEEN to every caller-owned IN_APP Notification whose deliveryStatus is
 * SENT/DELIVERED and that is not yet SEEN or ARCHIVED, stamps seenAt, and writes
 * one SEEN audit row per transition. SEEN is not READ and does not affect
 * unreadCount. Idempotent: a zero-row selection returns transitionedCount=0.
 */
export async function run(
  db: Transaction,
  input: MarkNotificationsAsSeenInput,
  ctx: CommandContext,
) {
  void input;

  // Select caller-owned, deliverable IN_APP rows whose engagementStatuses do
  // not yet contain SEEN. The command scopes to the IN_APP channel the same way
  // listInboxNotifications / markAllNotificationsAsRead do — rows dispatched on
  // other channels (e.g. EMAIL, terminal at SENT) must never be stamped SEEN.
  // Per-row containment of SEEN / ARCHIVED is filtered post-fetch to keep array
  // semantics out of the where clause; the database narrows on channel / owner /
  // status.
  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("ARCHIVED")) continue;
    if (row.engagementStatuses.includes("SEEN")) continue;

    const nextStatuses = [...row.engagementStatuses, "SEEN"];

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

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

    transitionedCount++;
  }

  return ok({ transitionedCount });
}
