import { z } from "zod";
import { normalizeTelegramCommandDescription, normalizeTelegramCommandName, resolveTelegramCustomCommands, } from "./telegram-custom-commands.js";
import { ToolPolicySchema } from "./zod-schema.agent-runtime.js";
import { ChannelHeartbeatVisibilitySchema } from "./zod-schema.channels.js";
import { BlockStreamingChunkSchema, BlockStreamingCoalesceSchema, DmConfigSchema, DmPolicySchema, ExecutableTokenSchema, GroupPolicySchema, MarkdownConfigSchema, MSTeamsReplyStyleSchema, ProviderCommandsSchema, ReplyToModeSchema, RetryConfigSchema, requireOpenAllowFrom, } from "./zod-schema.core.js";
const ToolPolicyBySenderSchema = z.record(z.string(), ToolPolicySchema).optional();
const TelegramInlineButtonsScopeSchema = z.enum(["off", "dm", "group", "all", "allowlist"]);
const TelegramCapabilitiesSchema = z.union([
    z.array(z.string()),
    z
        .object({
        inlineButtons: TelegramInlineButtonsScopeSchema.optional(),
    })
        .strict(),
]);
export const TelegramTopicSchema = z
    .object({
    requireMention: z.boolean().optional(),
    skills: z.array(z.string()).optional(),
    enabled: z.boolean().optional(),
    allowFrom: z.array(z.union([z.string(), z.number()])).optional(),
    systemPrompt: z.string().optional(),
})
    .strict();
export const TelegramGroupSchema = z
    .object({
    requireMention: z.boolean().optional(),
    tools: ToolPolicySchema,
    toolsBySender: ToolPolicyBySenderSchema,
    skills: z.array(z.string()).optional(),
    enabled: z.boolean().optional(),
    allowFrom: z.array(z.union([z.string(), z.number()])).optional(),
    systemPrompt: z.string().optional(),
    topics: z.record(z.string(), TelegramTopicSchema.optional()).optional(),
})
    .strict();
const TelegramCustomCommandSchema = z
    .object({
    command: z.string().transform(normalizeTelegramCommandName),
    description: z.string().transform(normalizeTelegramCommandDescription),
})
    .strict();
const validateTelegramCustomCommands = (value, ctx) => {
    if (!value.customCommands || value.customCommands.length === 0) {
        return;
    }
    const { issues } = resolveTelegramCustomCommands({
        commands: value.customCommands,
        checkReserved: false,
        checkDuplicates: false,
    });
    for (const issue of issues) {
        ctx.addIssue({
            code: z.ZodIssueCode.custom,
            path: ["customCommands", issue.index, issue.field],
            message: issue.message,
        });
    }
};
export const TelegramAccountSchemaBase = z
    .object({
    name: z.string().optional(),
    capabilities: TelegramCapabilitiesSchema.optional(),
    markdown: MarkdownConfigSchema,
    enabled: z.boolean().optional(),
    commands: ProviderCommandsSchema,
    customCommands: z.array(TelegramCustomCommandSchema).optional(),
    configWrites: z.boolean().optional(),
    dmPolicy: DmPolicySchema.optional().default("pairing"),
    botToken: z.string().optional(),
    tokenFile: z.string().optional(),
    replyToMode: ReplyToModeSchema.optional(),
    groups: z.record(z.string(), TelegramGroupSchema.optional()).optional(),
    allowFrom: z.array(z.union([z.string(), z.number()])).optional(),
    groupAllowFrom: z.array(z.union([z.string(), z.number()])).optional(),
    groupPolicy: GroupPolicySchema.optional().default("allowlist"),
    historyLimit: z.number().int().min(0).optional(),
    dmHistoryLimit: z.number().int().min(0).optional(),
    dms: z.record(z.string(), DmConfigSchema.optional()).optional(),
    textChunkLimit: z.number().int().positive().optional(),
    chunkMode: z.enum(["length", "newline"]).optional(),
    blockStreaming: z.boolean().optional(),
    draftChunk: BlockStreamingChunkSchema.optional(),
    blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
    streamMode: z.enum(["off", "partial", "block"]).optional().default("partial"),
    mediaMaxMb: z.number().positive().optional(),
    timeoutSeconds: z.number().int().positive().optional(),
    retry: RetryConfigSchema,
    network: z
        .object({
        autoSelectFamily: z.boolean().optional(),
    })
        .strict()
        .optional(),
    proxy: z.string().optional(),
    webhookUrl: z.string().optional(),
    webhookSecret: z.string().optional(),
    webhookPath: z.string().optional(),
    actions: z
        .object({
        reactions: z.boolean().optional(),
        sendMessage: z.boolean().optional(),
        deleteMessage: z.boolean().optional(),
        sticker: z.boolean().optional(),
    })
        .strict()
        .optional(),
    reactionNotifications: z.enum(["off", "own", "all"]).optional(),
    reactionLevel: z.enum(["off", "ack", "minimal", "extensive"]).optional(),
    heartbeat: ChannelHeartbeatVisibilitySchema,
    linkPreview: z.boolean().optional(),
})
    .strict();
export const TelegramAccountSchema = TelegramAccountSchemaBase.superRefine((value, ctx) => {
    requireOpenAllowFrom({
        policy: value.dmPolicy,
        allowFrom: value.allowFrom,
        ctx,
        path: ["allowFrom"],
        message: 'channels.telegram.dmPolicy="open" requires channels.telegram.allowFrom to include "*"',
    });
    validateTelegramCustomCommands(value, ctx);
});
export const TelegramConfigSchema = TelegramAccountSchemaBase.extend({
    accounts: z.record(z.string(), TelegramAccountSchema.optional()).optional(),
}).superRefine((value, ctx) => {
    requireOpenAllowFrom({
        policy: value.dmPolicy,
        allowFrom: value.allowFrom,
        ctx,
        path: ["allowFrom"],
        message: 'channels.telegram.dmPolicy="open" requires channels.telegram.allowFrom to include "*"',
    });
    validateTelegramCustomCommands(value, ctx);
});
export const DiscordDmSchema = z
    .object({
    enabled: z.boolean().optional(),
    policy: DmPolicySchema.optional().default("pairing"),
    allowFrom: z.array(z.union([z.string(), z.number()])).optional(),
    groupEnabled: z.boolean().optional(),
    groupChannels: z.array(z.union([z.string(), z.number()])).optional(),
})
    .strict()
    .superRefine((value, ctx) => {
    requireOpenAllowFrom({
        policy: value.policy,
        allowFrom: value.allowFrom,
        ctx,
        path: ["allowFrom"],
        message: 'channels.discord.dm.policy="open" requires channels.discord.dm.allowFrom to include "*"',
    });
});
export const DiscordGuildChannelSchema = z
    .object({
    allow: z.boolean().optional(),
    requireMention: z.boolean().optional(),
    tools: ToolPolicySchema,
    toolsBySender: ToolPolicyBySenderSchema,
    skills: z.array(z.string()).optional(),
    enabled: z.boolean().optional(),
    users: z.array(z.union([z.string(), z.number()])).optional(),
    systemPrompt: z.string().optional(),
    autoThread: z.boolean().optional(),
})
    .strict();
export const DiscordGuildSchema = z
    .object({
    slug: z.string().optional(),
    requireMention: z.boolean().optional(),
    tools: ToolPolicySchema,
    toolsBySender: ToolPolicyBySenderSchema,
    reactionNotifications: z.enum(["off", "own", "all", "allowlist"]).optional(),
    users: z.array(z.union([z.string(), z.number()])).optional(),
    channels: z.record(z.string(), DiscordGuildChannelSchema.optional()).optional(),
})
    .strict();
export const DiscordAccountSchema = z
    .object({
    name: z.string().optional(),
    capabilities: z.array(z.string()).optional(),
    markdown: MarkdownConfigSchema,
    enabled: z.boolean().optional(),
    commands: ProviderCommandsSchema,
    configWrites: z.boolean().optional(),
    token: z.string().optional(),
    allowBots: z.boolean().optional(),
    groupPolicy: GroupPolicySchema.optional().default("allowlist"),
    historyLimit: z.number().int().min(0).optional(),
    dmHistoryLimit: z.number().int().min(0).optional(),
    dms: z.record(z.string(), DmConfigSchema.optional()).optional(),
    textChunkLimit: z.number().int().positive().optional(),
    chunkMode: z.enum(["length", "newline"]).optional(),
    blockStreaming: z.boolean().optional(),
    blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
    maxLinesPerMessage: z.number().int().positive().optional(),
    mediaMaxMb: z.number().positive().optional(),
    retry: RetryConfigSchema,
    actions: z
        .object({
        reactions: z.boolean().optional(),
        stickers: z.boolean().optional(),
        emojiUploads: z.boolean().optional(),
        stickerUploads: z.boolean().optional(),
        polls: z.boolean().optional(),
        permissions: z.boolean().optional(),
        messages: z.boolean().optional(),
        threads: z.boolean().optional(),
        pins: z.boolean().optional(),
        search: z.boolean().optional(),
        memberInfo: z.boolean().optional(),
        roleInfo: z.boolean().optional(),
        roles: z.boolean().optional(),
        channelInfo: z.boolean().optional(),
        voiceStatus: z.boolean().optional(),
        events: z.boolean().optional(),
        moderation: z.boolean().optional(),
        channels: z.boolean().optional(),
    })
        .strict()
        .optional(),
    replyToMode: ReplyToModeSchema.optional(),
    dm: DiscordDmSchema.optional(),
    guilds: z.record(z.string(), DiscordGuildSchema.optional()).optional(),
    heartbeat: ChannelHeartbeatVisibilitySchema,
    execApprovals: z
        .object({
        enabled: z.boolean().optional(),
        approvers: z.array(z.union([z.string(), z.number()])).optional(),
        agentFilter: z.array(z.string()).optional(),
        sessionFilter: z.array(z.string()).optional(),
    })
        .strict()
        .optional(),
    intents: z
        .object({
        presence: z.boolean().optional(),
        guildMembers: z.boolean().optional(),
    })
        .strict()
        .optional(),
    pluralkit: z
        .object({
        enabled: z.boolean().optional(),
        token: z.string().optional(),
    })
        .strict()
        .optional(),
})
    .strict();
export const DiscordConfigSchema = DiscordAccountSchema.extend({
    accounts: z.record(z.string(), DiscordAccountSchema.optional()).optional(),
});
export const GoogleChatDmSchema = z
    .object({
    enabled: z.boolean().optional(),
    policy: DmPolicySchema.optional().default("pairing"),
    allowFrom: z.array(z.union([z.string(), z.number()])).optional(),
})
    .strict()
    .superRefine((value, ctx) => {
    requireOpenAllowFrom({
        policy: value.policy,
        allowFrom: value.allowFrom,
        ctx,
        path: ["allowFrom"],
        message: 'channels.googlechat.dm.policy="open" requires channels.googlechat.dm.allowFrom to include "*"',
    });
});
export const GoogleChatGroupSchema = z
    .object({
    enabled: z.boolean().optional(),
    allow: z.boolean().optional(),
    requireMention: z.boolean().optional(),
    users: z.array(z.union([z.string(), z.number()])).optional(),
    systemPrompt: z.string().optional(),
})
    .strict();
export const GoogleChatAccountSchema = z
    .object({
    name: z.string().optional(),
    capabilities: z.array(z.string()).optional(),
    enabled: z.boolean().optional(),
    configWrites: z.boolean().optional(),
    allowBots: z.boolean().optional(),
    requireMention: z.boolean().optional(),
    groupPolicy: GroupPolicySchema.optional().default("allowlist"),
    groupAllowFrom: z.array(z.union([z.string(), z.number()])).optional(),
    groups: z.record(z.string(), GoogleChatGroupSchema.optional()).optional(),
    serviceAccount: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
    serviceAccountFile: z.string().optional(),
    audienceType: z.enum(["app-url", "project-number"]).optional(),
    audience: z.string().optional(),
    webhookPath: z.string().optional(),
    webhookUrl: z.string().optional(),
    botUser: z.string().optional(),
    historyLimit: z.number().int().min(0).optional(),
    dmHistoryLimit: z.number().int().min(0).optional(),
    dms: z.record(z.string(), DmConfigSchema.optional()).optional(),
    textChunkLimit: z.number().int().positive().optional(),
    chunkMode: z.enum(["length", "newline"]).optional(),
    blockStreaming: z.boolean().optional(),
    blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
    mediaMaxMb: z.number().positive().optional(),
    replyToMode: ReplyToModeSchema.optional(),
    actions: z
        .object({
        reactions: z.boolean().optional(),
    })
        .strict()
        .optional(),
    dm: GoogleChatDmSchema.optional(),
    typingIndicator: z.enum(["none", "message", "reaction"]).optional(),
})
    .strict();
export const GoogleChatConfigSchema = GoogleChatAccountSchema.extend({
    accounts: z.record(z.string(), GoogleChatAccountSchema.optional()).optional(),
    defaultAccount: z.string().optional(),
});
export const SlackDmSchema = z
    .object({
    enabled: z.boolean().optional(),
    policy: DmPolicySchema.optional().default("pairing"),
    allowFrom: z.array(z.union([z.string(), z.number()])).optional(),
    groupEnabled: z.boolean().optional(),
    groupChannels: z.array(z.union([z.string(), z.number()])).optional(),
    replyToMode: ReplyToModeSchema.optional(),
})
    .strict()
    .superRefine((value, ctx) => {
    requireOpenAllowFrom({
        policy: value.policy,
        allowFrom: value.allowFrom,
        ctx,
        path: ["allowFrom"],
        message: 'channels.slack.dm.policy="open" requires channels.slack.dm.allowFrom to include "*"',
    });
});
export const SlackChannelSchema = z
    .object({
    enabled: z.boolean().optional(),
    allow: z.boolean().optional(),
    requireMention: z.boolean().optional(),
    tools: ToolPolicySchema,
    toolsBySender: ToolPolicyBySenderSchema,
    allowBots: z.boolean().optional(),
    users: z.array(z.union([z.string(), z.number()])).optional(),
    skills: z.array(z.string()).optional(),
    systemPrompt: z.string().optional(),
})
    .strict();
export const SlackThreadSchema = z
    .object({
    historyScope: z.enum(["thread", "channel"]).optional(),
    inheritParent: z.boolean().optional(),
})
    .strict();
const SlackReplyToModeByChatTypeSchema = z
    .object({
    direct: ReplyToModeSchema.optional(),
    group: ReplyToModeSchema.optional(),
    channel: ReplyToModeSchema.optional(),
})
    .strict();
export const SlackAccountSchema = z
    .object({
    name: z.string().optional(),
    mode: z.enum(["socket", "http"]).optional(),
    signingSecret: z.string().optional(),
    webhookPath: z.string().optional(),
    capabilities: z.array(z.string()).optional(),
    markdown: MarkdownConfigSchema,
    enabled: z.boolean().optional(),
    commands: ProviderCommandsSchema,
    configWrites: z.boolean().optional(),
    botToken: z.string().optional(),
    appToken: z.string().optional(),
    userToken: z.string().optional(),
    userTokenReadOnly: z.boolean().optional().default(true),
    allowBots: z.boolean().optional(),
    requireMention: z.boolean().optional(),
    groupPolicy: GroupPolicySchema.optional().default("allowlist"),
    historyLimit: z.number().int().min(0).optional(),
    dmHistoryLimit: z.number().int().min(0).optional(),
    dms: z.record(z.string(), DmConfigSchema.optional()).optional(),
    textChunkLimit: z.number().int().positive().optional(),
    chunkMode: z.enum(["length", "newline"]).optional(),
    blockStreaming: z.boolean().optional(),
    blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
    mediaMaxMb: z.number().positive().optional(),
    reactionNotifications: z.enum(["off", "own", "all", "allowlist"]).optional(),
    reactionAllowlist: z.array(z.union([z.string(), z.number()])).optional(),
    replyToMode: ReplyToModeSchema.optional(),
    replyToModeByChatType: SlackReplyToModeByChatTypeSchema.optional(),
    thread: SlackThreadSchema.optional(),
    actions: z
        .object({
        reactions: z.boolean().optional(),
        messages: z.boolean().optional(),
        pins: z.boolean().optional(),
        search: z.boolean().optional(),
        permissions: z.boolean().optional(),
        memberInfo: z.boolean().optional(),
        channelInfo: z.boolean().optional(),
        emojiList: z.boolean().optional(),
    })
        .strict()
        .optional(),
    slashCommand: z
        .object({
        enabled: z.boolean().optional(),
        name: z.string().optional(),
        sessionPrefix: z.string().optional(),
        ephemeral: z.boolean().optional(),
    })
        .strict()
        .optional(),
    dm: SlackDmSchema.optional(),
    channels: z.record(z.string(), SlackChannelSchema.optional()).optional(),
    heartbeat: ChannelHeartbeatVisibilitySchema,
})
    .strict();
export const SlackConfigSchema = SlackAccountSchema.extend({
    mode: z.enum(["socket", "http"]).optional().default("socket"),
    signingSecret: z.string().optional(),
    webhookPath: z.string().optional().default("/slack/events"),
    accounts: z.record(z.string(), SlackAccountSchema.optional()).optional(),
}).superRefine((value, ctx) => {
    const baseMode = value.mode ?? "socket";
    if (baseMode === "http" && !value.signingSecret) {
        ctx.addIssue({
            code: z.ZodIssueCode.custom,
            message: 'channels.slack.mode="http" requires channels.slack.signingSecret',
            path: ["signingSecret"],
        });
    }
    if (!value.accounts) {
        return;
    }
    for (const [accountId, account] of Object.entries(value.accounts)) {
        if (!account) {
            continue;
        }
        if (account.enabled === false) {
            continue;
        }
        const accountMode = account.mode ?? baseMode;
        if (accountMode !== "http") {
            continue;
        }
        const accountSecret = account.signingSecret ?? value.signingSecret;
        if (!accountSecret) {
            ctx.addIssue({
                code: z.ZodIssueCode.custom,
                message: 'channels.slack.accounts.*.mode="http" requires channels.slack.signingSecret or channels.slack.accounts.*.signingSecret',
                path: ["accounts", accountId, "signingSecret"],
            });
        }
    }
});
export const SignalAccountSchemaBase = z
    .object({
    name: z.string().optional(),
    capabilities: z.array(z.string()).optional(),
    markdown: MarkdownConfigSchema,
    enabled: z.boolean().optional(),
    configWrites: z.boolean().optional(),
    account: z.string().optional(),
    httpUrl: z.string().optional(),
    httpHost: z.string().optional(),
    httpPort: z.number().int().positive().optional(),
    cliPath: ExecutableTokenSchema.optional(),
    autoStart: z.boolean().optional(),
    startupTimeoutMs: z.number().int().min(1000).max(120000).optional(),
    receiveMode: z.union([z.literal("on-start"), z.literal("manual")]).optional(),
    ignoreAttachments: z.boolean().optional(),
    ignoreStories: z.boolean().optional(),
    sendReadReceipts: z.boolean().optional(),
    dmPolicy: DmPolicySchema.optional().default("pairing"),
    allowFrom: z.array(z.union([z.string(), z.number()])).optional(),
    groupAllowFrom: z.array(z.union([z.string(), z.number()])).optional(),
    groupPolicy: GroupPolicySchema.optional().default("allowlist"),
    historyLimit: z.number().int().min(0).optional(),
    dmHistoryLimit: z.number().int().min(0).optional(),
    dms: z.record(z.string(), DmConfigSchema.optional()).optional(),
    textChunkLimit: z.number().int().positive().optional(),
    chunkMode: z.enum(["length", "newline"]).optional(),
    blockStreaming: z.boolean().optional(),
    blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
    mediaMaxMb: z.number().int().positive().optional(),
    reactionNotifications: z.enum(["off", "own", "all", "allowlist"]).optional(),
    reactionAllowlist: z.array(z.union([z.string(), z.number()])).optional(),
    actions: z
        .object({
        reactions: z.boolean().optional(),
    })
        .strict()
        .optional(),
    reactionLevel: z.enum(["off", "ack", "minimal", "extensive"]).optional(),
    heartbeat: ChannelHeartbeatVisibilitySchema,
})
    .strict();
export const SignalAccountSchema = SignalAccountSchemaBase.superRefine((value, ctx) => {
    requireOpenAllowFrom({
        policy: value.dmPolicy,
        allowFrom: value.allowFrom,
        ctx,
        path: ["allowFrom"],
        message: 'channels.signal.dmPolicy="open" requires channels.signal.allowFrom to include "*"',
    });
});
export const SignalConfigSchema = SignalAccountSchemaBase.extend({
    accounts: z.record(z.string(), SignalAccountSchema.optional()).optional(),
}).superRefine((value, ctx) => {
    requireOpenAllowFrom({
        policy: value.dmPolicy,
        allowFrom: value.allowFrom,
        ctx,
        path: ["allowFrom"],
        message: 'channels.signal.dmPolicy="open" requires channels.signal.allowFrom to include "*"',
    });
});
export const IMessageAccountSchemaBase = z
    .object({
    name: z.string().optional(),
    capabilities: z.array(z.string()).optional(),
    markdown: MarkdownConfigSchema,
    enabled: z.boolean().optional(),
    configWrites: z.boolean().optional(),
    cliPath: ExecutableTokenSchema.optional(),
    dbPath: z.string().optional(),
    remoteHost: z.string().optional(),
    service: z.union([z.literal("imessage"), z.literal("sms"), z.literal("auto")]).optional(),
    region: z.string().optional(),
    dmPolicy: DmPolicySchema.optional().default("pairing"),
    allowFrom: z.array(z.union([z.string(), z.number()])).optional(),
    groupAllowFrom: z.array(z.union([z.string(), z.number()])).optional(),
    groupPolicy: GroupPolicySchema.optional().default("allowlist"),
    historyLimit: z.number().int().min(0).optional(),
    dmHistoryLimit: z.number().int().min(0).optional(),
    dms: z.record(z.string(), DmConfigSchema.optional()).optional(),
    includeAttachments: z.boolean().optional(),
    mediaMaxMb: z.number().int().positive().optional(),
    textChunkLimit: z.number().int().positive().optional(),
    chunkMode: z.enum(["length", "newline"]).optional(),
    blockStreaming: z.boolean().optional(),
    blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
    groups: z
        .record(z.string(), z
        .object({
        requireMention: z.boolean().optional(),
        tools: ToolPolicySchema,
        toolsBySender: ToolPolicyBySenderSchema,
    })
        .strict()
        .optional())
        .optional(),
    heartbeat: ChannelHeartbeatVisibilitySchema,
})
    .strict();
export const IMessageAccountSchema = IMessageAccountSchemaBase.superRefine((value, ctx) => {
    requireOpenAllowFrom({
        policy: value.dmPolicy,
        allowFrom: value.allowFrom,
        ctx,
        path: ["allowFrom"],
        message: 'channels.imessage.dmPolicy="open" requires channels.imessage.allowFrom to include "*"',
    });
});
export const IMessageConfigSchema = IMessageAccountSchemaBase.extend({
    accounts: z.record(z.string(), IMessageAccountSchema.optional()).optional(),
}).superRefine((value, ctx) => {
    requireOpenAllowFrom({
        policy: value.dmPolicy,
        allowFrom: value.allowFrom,
        ctx,
        path: ["allowFrom"],
        message: 'channels.imessage.dmPolicy="open" requires channels.imessage.allowFrom to include "*"',
    });
});
const BlueBubblesAllowFromEntry = z.union([z.string(), z.number()]);
const BlueBubblesActionSchema = z
    .object({
    reactions: z.boolean().optional(),
    edit: z.boolean().optional(),
    unsend: z.boolean().optional(),
    reply: z.boolean().optional(),
    sendWithEffect: z.boolean().optional(),
    renameGroup: z.boolean().optional(),
    setGroupIcon: z.boolean().optional(),
    addParticipant: z.boolean().optional(),
    removeParticipant: z.boolean().optional(),
    leaveGroup: z.boolean().optional(),
    sendAttachment: z.boolean().optional(),
})
    .strict()
    .optional();
const BlueBubblesGroupConfigSchema = z
    .object({
    requireMention: z.boolean().optional(),
    tools: ToolPolicySchema,
    toolsBySender: ToolPolicyBySenderSchema,
})
    .strict();
export const BlueBubblesAccountSchemaBase = z
    .object({
    name: z.string().optional(),
    capabilities: z.array(z.string()).optional(),
    markdown: MarkdownConfigSchema,
    configWrites: z.boolean().optional(),
    enabled: z.boolean().optional(),
    serverUrl: z.string().optional(),
    password: z.string().optional(),
    webhookPath: z.string().optional(),
    dmPolicy: DmPolicySchema.optional().default("pairing"),
    allowFrom: z.array(BlueBubblesAllowFromEntry).optional(),
    groupAllowFrom: z.array(BlueBubblesAllowFromEntry).optional(),
    groupPolicy: GroupPolicySchema.optional().default("allowlist"),
    historyLimit: z.number().int().min(0).optional(),
    dmHistoryLimit: z.number().int().min(0).optional(),
    dms: z.record(z.string(), DmConfigSchema.optional()).optional(),
    textChunkLimit: z.number().int().positive().optional(),
    chunkMode: z.enum(["length", "newline"]).optional(),
    mediaMaxMb: z.number().int().positive().optional(),
    sendReadReceipts: z.boolean().optional(),
    blockStreaming: z.boolean().optional(),
    blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
    groups: z.record(z.string(), BlueBubblesGroupConfigSchema.optional()).optional(),
    heartbeat: ChannelHeartbeatVisibilitySchema,
})
    .strict();
export const BlueBubblesAccountSchema = BlueBubblesAccountSchemaBase.superRefine((value, ctx) => {
    requireOpenAllowFrom({
        policy: value.dmPolicy,
        allowFrom: value.allowFrom,
        ctx,
        path: ["allowFrom"],
        message: 'channels.bluebubbles.accounts.*.dmPolicy="open" requires allowFrom to include "*"',
    });
});
export const BlueBubblesConfigSchema = BlueBubblesAccountSchemaBase.extend({
    accounts: z.record(z.string(), BlueBubblesAccountSchema.optional()).optional(),
    actions: BlueBubblesActionSchema,
}).superRefine((value, ctx) => {
    requireOpenAllowFrom({
        policy: value.dmPolicy,
        allowFrom: value.allowFrom,
        ctx,
        path: ["allowFrom"],
        message: 'channels.bluebubbles.dmPolicy="open" requires channels.bluebubbles.allowFrom to include "*"',
    });
});
export const MSTeamsChannelSchema = z
    .object({
    requireMention: z.boolean().optional(),
    tools: ToolPolicySchema,
    toolsBySender: ToolPolicyBySenderSchema,
    replyStyle: MSTeamsReplyStyleSchema.optional(),
})
    .strict();
export const MSTeamsTeamSchema = z
    .object({
    requireMention: z.boolean().optional(),
    tools: ToolPolicySchema,
    toolsBySender: ToolPolicyBySenderSchema,
    replyStyle: MSTeamsReplyStyleSchema.optional(),
    channels: z.record(z.string(), MSTeamsChannelSchema.optional()).optional(),
})
    .strict();
export const MSTeamsConfigSchema = z
    .object({
    enabled: z.boolean().optional(),
    capabilities: z.array(z.string()).optional(),
    markdown: MarkdownConfigSchema,
    configWrites: z.boolean().optional(),
    appId: z.string().optional(),
    appPassword: z.string().optional(),
    tenantId: z.string().optional(),
    webhook: z
        .object({
        port: z.number().int().positive().optional(),
        path: z.string().optional(),
    })
        .strict()
        .optional(),
    dmPolicy: DmPolicySchema.optional().default("pairing"),
    allowFrom: z.array(z.string()).optional(),
    groupAllowFrom: z.array(z.string()).optional(),
    groupPolicy: GroupPolicySchema.optional().default("allowlist"),
    textChunkLimit: z.number().int().positive().optional(),
    chunkMode: z.enum(["length", "newline"]).optional(),
    blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
    mediaAllowHosts: z.array(z.string()).optional(),
    requireMention: z.boolean().optional(),
    historyLimit: z.number().int().min(0).optional(),
    dmHistoryLimit: z.number().int().min(0).optional(),
    dms: z.record(z.string(), DmConfigSchema.optional()).optional(),
    replyStyle: MSTeamsReplyStyleSchema.optional(),
    teams: z.record(z.string(), MSTeamsTeamSchema.optional()).optional(),
    /** Max media size in MB (default: 100MB for OneDrive upload support). */
    mediaMaxMb: z.number().positive().optional(),
    /** SharePoint site ID for file uploads in group chats/channels (e.g., "contoso.sharepoint.com,guid1,guid2") */
    sharePointSiteId: z.string().optional(),
    heartbeat: ChannelHeartbeatVisibilitySchema,
})
    .strict()
    .superRefine((value, ctx) => {
    requireOpenAllowFrom({
        policy: value.dmPolicy,
        allowFrom: value.allowFrom,
        ctx,
        path: ["allowFrom"],
        message: 'channels.msteams.dmPolicy="open" requires channels.msteams.allowFrom to include "*"',
    });
});
