import {
  type CommonReservedFields,
  type NoReservedFields,
  defaultGqlPermission,
  defaultPermission,
} from "@tailor-platform/erp-kit/core";
import { db, type TailorAnyDBField } from "@tailor-platform/sdk";
import { NOTIFICATION_REASONS } from "../lib/events";
import { notificationLifecycle } from "./notification.lifecycle.generated";
import { notificationChannel } from "./notificationChannel";

/** Delivery-axis states of a Notification (e.g. QUEUED, SENT, DELIVERED, FAILED, BOUNCED). */
export const NOTIFICATION_DELIVERY_STATUSES = notificationLifecycle.states;

/** Engagement states a Notification can accumulate (SEEN, READ, ARCHIVED). */
export const NOTIFICATION_ENGAGEMENT_STATUSES = ["SEEN", "READ", "ARCHIVED"] as const;

const builtins = {
  recipientUserId: db
    .string()
    .description("Recipient user id; replaced with TOMBSTONED when the row has been anonymized"),
  channelId: db
    .uuid()
    .relation({
      type: "n-1",
      toward: { type: notificationChannel },
      backward: "notifications",
    })
    .description("Foreign key to NotificationChannel this row was dispatched on"),
  eventType: db.string().description("Event type key resolved at dispatch time"),
  sourceType: db
    .string()
    .description("Polymorphic source-record discriminator owned by the emitting module"),
  sourceId: db.string().description("Polymorphic source-record id; no FK constraint"),
  reason: db
    .enum(NOTIFICATION_REASONS)
    .description(
      "Resolved inclusion reason (SUBSCRIBED/ASSIGNED/AUTHOR/MENTION). ASSIGNED/MENTION trigger the critical bypass over a preference mute",
    ),
  locale: db.string().description("Locale used to render this row's subject and body"),
  payloadVars: db
    .string({ optional: true })
    .description(
      "JSON-encoded payload variables supplied by the emitter; cleared on anonymization",
    ),
  subject: db
    .string()
    .description(
      "Rendered subject captured at dispatch (immutable; replaced with TOMBSTONED on anonymization)",
    ),
  body: db
    .string()
    .description(
      "Rendered plain-text body captured at dispatch (immutable; replaced with TOMBSTONED on anonymization)",
    ),
  htmlBody: db
    .string({ optional: true })
    .description("Rendered HTML body for channels that support it; cleared on anonymization"),
  idempotencyKey: db
    .string()
    .description("Per-recipient dedup key; uniqueness enforced with channelId + recipientUserId"),
  deliveryStatus: db
    .enum(NOTIFICATION_DELIVERY_STATUSES)
    .description("Linear delivery axis (QUEUED, SENT, DELIVERED, FAILED, BOUNCED)"),
  engagementStatuses: db
    .string({ array: true })
    .description("Monotonic engagement set (SEEN, READ, ARCHIVED)"),
  seenAt: db
    .datetime({ optional: true })
    .description("First time SEEN was added to engagementStatuses"),
  readAt: db
    .datetime({ optional: true })
    .description("First time READ was added to engagementStatuses"),
  archivedAt: db
    .datetime({ optional: true })
    .description("First time ARCHIVED was added to engagementStatuses"),
  adapterMessageId: db
    .string({ optional: true })
    .description("Optional provider message id returned by the channel adapter on success"),
};

type ReservedFields = keyof typeof builtins | CommonReservedFields;

export interface CreateNotificationTypeParams<F extends Record<string, TailorAnyDBField>> {
  fields?: NoReservedFields<F, ReservedFields>;
}

export function createNotificationType<const F extends Record<string, TailorAnyDBField>>(
  params: CreateNotificationTypeParams<F>,
) {
  return db
    .type("Notification", {
      ...builtins,
      ...((params.fields ?? {}) as F),
      ...db.fields.timestamps(),
    })
    .indexes({
      fields: ["recipientUserId", "channelId", "idempotencyKey"],
      unique: true,
      name: "notification_idempotency_unique_idx",
    })
    .permission(defaultPermission)
    .gqlPermission(defaultGqlPermission);
}

export const notification = createNotificationType({});
