import { z } from "zod";
import { Blocks, Ulid } from "./entities";

export const CreateDirectMessageRequest = z.object({ otherUserId: Ulid });
export const CreateGroupDirectMessageRequest = z.object({
  memberUserIds: z.array(Ulid).min(2).max(8),
});

export const UpdateChannelRequest = z.object({
  name: z.string().min(1).max(80).optional(),
  topic: z.string().max(250).optional(),
  purpose: z.string().max(500).optional(),
});

export const ArchiveChannelRequest = z.object({ archived: z.boolean() });

/**
 * Per-user, per-room notification setting — stored on channel_members, so two
 * people in the same room can (and usually do) hold different values. `all`
 * notifies on every message, `mentions` only when you're named, `none` never.
 * Muting is orthogonal: it silences the badge/highlight in the sidebar without
 * changing which messages would otherwise notify.
 */
export const ChannelNotifPref = z.enum(["all", "mentions", "none"]);
export type ChannelNotifPref = z.infer<typeof ChannelNotifPref>;

export const UpdateChannelPrefsRequest = z
  .object({
    notifPref: ChannelNotifPref.optional(),
    isMuted: z.boolean().optional(),
    isStarred: z.boolean().optional(),
  })
  .refine((v) => Object.keys(v).length > 0, { message: "no preference fields supplied" });
export type UpdateChannelPrefsRequest = z.infer<typeof UpdateChannelPrefsRequest>;

/**
 * The apps a room can link. A closed list rather than free text: the About
 * panel renders a known badge per provider, and an unbounded string would
 * make that a rendering guess. `custom` is the escape hatch — it carries its
 * own label.
 */
export const IntegrationProvider = z.enum([
  "salesforce",
  "hubspot",
  "github",
  "jira",
  "linear",
  "notion",
  "zoom",
  "google_drive",
  "custom",
]);
export type IntegrationProvider = z.infer<typeof IntegrationProvider>;

export const AddChannelIntegrationRequest = z.object({
  provider: IntegrationProvider,
  label: z.string().min(1).max(60).optional(),
  externalUrl: z.string().url().max(2000).optional(),
});
export type AddChannelIntegrationRequest = z.infer<typeof AddChannelIntegrationRequest>;

export const AddChannelMembersRequest = z.object({
  userIds: z.array(Ulid).min(1).max(50),
});
export type AddChannelMembersRequest = z.infer<typeof AddChannelMembersRequest>;

export const SetDirectMessageClosedRequest = z.object({ closed: z.boolean() });
export type SetDirectMessageClosedRequest = z.infer<typeof SetDirectMessageClosedRequest>;

export const ConvertGroupDirectMessageRequest = z.object({
  name: z.string().trim().min(1).max(80),
});
export type ConvertGroupDirectMessageRequest = z.infer<typeof ConvertGroupDirectMessageRequest>;

export const EditMessageRequest = z.object({
  text: z.string().min(1).max(40_000),
  blocks: z.unknown().optional(),
});

export const ForwardMessageRequest = z.object({
  destinations: z.array(z.object({
    channelId: Ulid,
    clientMsgId: z.string().uuid(),
  })).min(1).max(10).superRefine((destinations, ctx) => {
    const ids = destinations.map((destination) => destination.channelId);
    if (new Set(ids).size !== ids.length) ctx.addIssue({ code: "custom", message: "duplicate destination channel" });
  }),
  note: z.string().max(2_000).optional().default(""),
});
export type ForwardMessageRequest = z.infer<typeof ForwardMessageRequest>;

export const SetReactionRequest = z.object({ emoji: z.string().min(1).max(64) });

export const MarkChannelReadRequest = z.object({ seq: z.number().int().nonnegative() });
export const MarkThreadReadRequest = z.object({ seq: z.number().int().nonnegative() });
export const SetThreadFollowingRequest = z.object({ following: z.boolean() });

export const UpsertDraftRequest = z.object({
  channelId: Ulid,
  threadRootMessageId: Ulid.nullable().optional(),
  text: z.string().max(40_000),
  blocks: Blocks.optional(),
});
export type UpsertDraftRequest = z.infer<typeof UpsertDraftRequest>;

export const DeleteDraftRequest = z.object({
  channelId: Ulid,
  threadRootMessageId: Ulid.nullable().optional(),
});
export type DeleteDraftRequest = z.infer<typeof DeleteDraftRequest>;

export const UpdateNotificationPreferencesRequest = z
  .object({
    messages: z.enum(["all", "mentions", "off"]).optional(),
    calls: z.boolean().optional(),
    tasks: z.boolean().optional(),
    calendar: z.boolean().optional(),
    sound: z.boolean().optional(),
    inAppFlash: z.boolean().optional(),
  })
  .refine((value) => Object.keys(value).length > 0, { message: "no notification preference fields supplied" });
export type UpdateNotificationPreferencesRequest = z.infer<typeof UpdateNotificationPreferencesRequest>;

export const UpdateActivityReadRequest = z.object({
  messageIds: z.array(Ulid).min(1).max(100),
  read: z.boolean(),
});
export type UpdateActivityReadRequest = z.infer<typeof UpdateActivityReadRequest>;
