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

export interface GetEffectiveNotificationPreferenceInput {
  userId: string;
  eventType: string;
  channelKey: string;
}

export type EffectiveSource = "TRANSACTIONAL_OVERRIDE" | "USER_PREFERENCE" | "DEFAULT";

export interface EffectivePreference {
  allowed: boolean;
  source: EffectiveSource;
}

/**
 * Resolves the effective dispatch decision for a (userId, eventType, channelKey)
 * triple, composing the dispatcher's gate stack in order: transactional override,
 * the user's NotificationPreference row, then the default opt-in. Returns
 * `{ allowed, source }` disclosing which layer decided. The reason-driven critical
 * bypass is intentionally out of scope.
 */
export async function run(
  db: ReadonlyDB<DB>,
  input: GetEffectiveNotificationPreferenceInput,
  ctx: QueryContext,
) {
  const { userId, eventType, channelKey } = input;

  if (ctx.actorId !== userId) {
    return err(new ForbiddenError(userId));
  }

  const binding = await db
    .selectFrom("EventCategoryBinding")
    .selectAll()
    .where("eventType", "=", eventType)
    .executeTakeFirst();

  if (!binding) {
    return err(new CategoryNotFoundError(eventType));
  }

  const category = await db
    .selectFrom("NotificationCategory")
    .select(["optOutAllowed"])
    .where("id", "=", binding.categoryId)
    .executeTakeFirst();

  const transactional = Boolean(binding.transactional) || category?.optOutAllowed === false;
  if (transactional) {
    return ok({
      effective: {
        allowed: true,
        source: "TRANSACTIONAL_OVERRIDE" as const,
      } satisfies EffectivePreference,
    });
  }

  const channel = await loadChannelByChannelId(db, channelKey);
  if (!channel) {
    return err(new ChannelNotFoundError(channelKey));
  }

  const preference = await db
    .selectFrom("NotificationPreference")
    .selectAll()
    .where("userId", "=", userId)
    .where("categoryId", "=", binding.categoryId)
    .where("channelId", "=", channel.id)
    .executeTakeFirst();

  if (preference) {
    return ok({
      effective: {
        allowed: preference.allowed,
        source: "USER_PREFERENCE" as const,
      } satisfies EffectivePreference,
    });
  }

  return ok({
    effective: {
      allowed: true,
      source: "DEFAULT" as const,
    } satisfies EffectivePreference,
  });
}
