import { ok, err, type ReadonlyDB } from "@tailor-platform/erp-kit/core";
import { parseVariableSchema } from "../command/createNotificationTemplate";
import type { DB } from "../generated/kysely-tailordb";
import { TemplateNotFoundError, TemplateVarValidationFailedError } from "../lib/errors.generated";
import { interpolate, validatePayloadVars } from "../lib/templateRendering";

export interface RenderNotificationTemplateInput {
  eventType: string;
  channelId: string;
  locale: string;
  payloadVars?: Record<string, unknown>;
  /** Optional default-locale override; falls back to `en-US`. */
  defaultLocale?: string;
}

const DEFAULT_LOCALE = "en-US";

/**
 * Renders a template's subject/body (and optional HTML body) for an (eventType, channelId, locale) with default-locale fallback and variable-schema validation.
 */
export async function run(db: ReadonlyDB<DB>, input: RenderNotificationTemplateInput) {
  const { eventType, channelId, locale, payloadVars = {} } = input;
  const defaultLocale = input.defaultLocale ?? DEFAULT_LOCALE;

  let template = await db
    .selectFrom("NotificationTemplate")
    .selectAll()
    .where("eventType", "=", eventType)
    .where("channelId", "=", channelId)
    .where("locale", "=", locale)
    .executeTakeFirst();

  if (!template && locale !== defaultLocale) {
    template = await db
      .selectFrom("NotificationTemplate")
      .selectAll()
      .where("eventType", "=", eventType)
      .where("channelId", "=", channelId)
      .where("locale", "=", defaultLocale)
      .executeTakeFirst();
  }

  if (!template) {
    return err(new TemplateNotFoundError(eventType));
  }

  const schema = parseVariableSchema(template.variableSchema);
  if (!schema) {
    return err(new TemplateVarValidationFailedError("invalid variableSchema"));
  }

  const validationError = validatePayloadVars(schema, payloadVars);
  if (validationError) {
    return err(new TemplateVarValidationFailedError(validationError));
  }

  const subject = interpolate(template.subject, payloadVars, false);
  const body = interpolate(template.body, payloadVars, false);
  const htmlBody =
    template.htmlBody !== null && template.htmlBody !== undefined
      ? interpolate(template.htmlBody, payloadVars, true)
      : undefined;

  return ok({ subject, body, htmlBody });
}
