import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/core";
import type { Transaction } from "../generated/kysely-tailordb";
import { ChannelNotFoundError, MissingRequiredFieldError } from "../lib/errors.generated";
import type { ChannelCapabilities, ChannelId } from "./createNotificationChannel";

export interface UpdateNotificationChannelInput {
  channelId: ChannelId;
  displayName?: string;
  capabilities?: ChannelCapabilities;
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return Boolean(value) && typeof value === "object";
}

function hasAllCapabilityKeys(value: unknown): value is ChannelCapabilities {
  if (!isRecord(value)) return false;
  return (
    typeof value.supportsHtmlBody === "boolean" &&
    typeof value.supportsAttachments === "boolean" &&
    typeof value.supportsRichActions === "boolean"
  );
}

/**
 * Updates a registered NotificationChannel's displayName and/or capabilities. Never changes channelId, kind, or enabled; errors when the channel is not registered.
 */
export async function run(
  db: Transaction,
  input: UpdateNotificationChannelInput,
  _ctx: CommandContext,
) {
  const { channelId, displayName, capabilities } = input;

  if (!channelId) {
    return err(new MissingRequiredFieldError("channelId"));
  }

  const existing = await db
    .selectFrom("NotificationChannel")
    .selectAll()
    .where("channelId", "=", channelId)
    .forUpdate()
    .executeTakeFirst();

  if (!existing) {
    return err(new ChannelNotFoundError(channelId));
  }

  const updates: {
    displayName?: string;
    capabilities?: ChannelCapabilities;
    updatedAt: Date;
  } = { updatedAt: new Date() };

  if (displayName !== undefined) {
    const trimmed = displayName.trim();
    if (trimmed === "") {
      return err(new MissingRequiredFieldError("displayName"));
    }
    updates.displayName = trimmed;
  }

  if (capabilities !== undefined) {
    if (!hasAllCapabilityKeys(capabilities)) {
      return err(new MissingRequiredFieldError("capabilities"));
    }
    updates.capabilities = capabilities;
  }

  const channel = await db
    .updateTable("NotificationChannel")
    .set(updates)
    .where("channelId", "=", channelId)
    .returningAll()
    .executeTakeFirstOrThrow();

  return ok({ channel });
}
