import { z } from "zod";

const optionalText = (max: number, message: string) => z.string().trim().max(max, message).optional().default("");
const roomSeatCandidates = [10, 15, 20, 25, 30] as const;
const robotUserIdSchema = (message: string) =>
    z
        .union([z.string(), z.number()])
        .transform((value) => String(value).trim())
        .refine((value) => /^[1-9]\d*$/.test(value), message);
const countryCodeSchema = z
    .string()
    .trim()
    .transform((value) => value.toUpperCase())
    .refine((value) => /^[A-Z]{2,3}$/.test(value), "国家码不正确");
const commaSeparatedTextListSchema = z
    .union([z.string(), z.array(z.union([z.string(), z.number()]))])
    .optional()
    .default("")
    .transform((value) => {
        const raw = Array.isArray(value) ? value.join(",") : value;
        return [
            ...new Set(
                String(raw || "")
                    .split(",")
                    .map((item) => item.trim())
                    .filter(Boolean),
            ),
        ];
    });
const pinTypeSchema = z
    .string()
    .trim()
    .refine((value) => value === "region" || value === "country" || value === "global", "请选择置顶类型")
    .default("region");
const dateTimeMsSchema = z.union([z.string(), z.number()]).transform((value, context) => {
    if (typeof value === "number" && Number.isFinite(value)) {
        return value;
    }
    const ms = Date.parse(String(value || "").trim());
    if (!Number.isFinite(ms)) {
        context.addIssue({ code: z.ZodIssueCode.custom, message: "请选择置顶时间" });
        return z.NEVER;
    }
    return ms;
});

export const roomUpdateSchema = z.object({
    coverUrl: optionalText(512, "房间头像不能超过 512 个字符"),
    description: optionalText(512, "房间简介不能超过 512 个字符"),
    title: z.string().trim().min(1, "请输入房间名称").max(128, "房间名称不能超过 128 个字符"),
    visibleRegionId: z.coerce.number().int().min(0, "区域 ID 不正确").default(0),
});

export const roomStatusSchema = z
    .object({
        closeReason: z.string().trim().max(512, "关闭原因不能超过 512 个字符").optional().default(""),
        status: z
            .string()
            .trim()
            .refine((value) => value === "active" || value === "closed", "房间状态不正确"),
    })
    .refine((value) => value.status !== "closed" || value.closeReason.length > 0, {
        message: "请输入关闭原因",
        path: ["closeReason"],
    });

export const roomConfigSchema = z
    .object({
        allowedSeatCounts: z
            .array(z.coerce.number().int())
            .min(1, "至少启用一个座位数")
            .refine(
                (values) =>
                    values.every((value) => roomSeatCandidates.includes(value as (typeof roomSeatCandidates)[number])),
                "座位数只能选择 10、15、20、25、30",
            )
            .refine((values) => new Set(values).size === values.length, "座位数不能重复"),
        defaultSeatCount: z.coerce.number().int(),
    })
    .refine((value) => value.allowedSeatCounts.includes(value.defaultSeatCount), {
        message: "默认座位数必须在已启用座位数中",
        path: ["defaultSeatCount"],
    });

export const roomWhitelistSchema = z.object({
    userIds: z
        .array(
            z
                .union([z.string(), z.number()])
                .transform((value) => String(value).trim())
                .refine((value) => /^[1-9]\d*$/.test(value), "用户 ID 不正确"),
        )
        .default([])
        .transform((values) =>
            [...new Set(values)].sort((left, right) => left.localeCompare(right, "en", { numeric: true })),
        ),
});

export const roomPinCreateSchema = z
    .object({
        expiresAtMs: dateTimeMsSchema,
        pinType: pinTypeSchema,
        pinnedAtMs: dateTimeMsSchema,
        roomId: z.string().trim().min(1, "请选择房间").max(64, "房间 ID 不正确"),
        weight: z.coerce.number().int().min(0, "排序不能小于 0").default(0),
    })
    .refine((value) => value.expiresAtMs > value.pinnedAtMs, {
        message: "结束时间必须晚于开始时间",
        path: ["expiresAtMs"],
    });

export const robotRoomCreateSchema = z
    .object({
        candidateRobotUserIds: z.array(robotUserIdSchema("请选择候选机器人")).min(1, "请选择候选机器人"),
        giftIds: z.array(z.string().trim().min(1)).min(1, "请选择普通礼物合集"),
        luckyComboMax: z.coerce.number().int().min(1, "幸运礼物连击范围不正确"),
        luckyComboMin: z.coerce.number().int().min(1, "幸运礼物连击范围不正确"),
        luckyGiftIds: z.array(z.string().trim().min(1)).min(1, "请选择幸运礼物合集"),
        luckyPauseMaxMs: z.coerce.number().int().min(1000, "幸运礼物间隔范围不正确"),
        luckyPauseMinMs: z.coerce.number().int().min(1000, "幸运礼物间隔范围不正确"),
        maxGiftSenders: z.coerce.number().int().min(1, "同时送礼机器人数量不正确"),
        maxRobotCount: z.coerce.number().int().min(1, "机器人数量范围不正确"),
        minRobotCount: z.coerce.number().int().min(1, "机器人数量范围不正确"),
        normalGiftIntervalMs: z.coerce.number().int().min(1000, "普通礼物频次不正确"),
        ownerRobotUserId: robotUserIdSchema("请选择房主机器人"),
        robotReplaceMaxMs: z.coerce.number().int().min(0, "机器人补位时间范围不正确"),
        robotReplaceMinMs: z.coerce.number().int().min(0, "机器人补位时间范围不正确"),
        robotStayMaxMs: z.coerce.number().int().min(1000, "机器人停留时间范围不正确"),
        robotStayMinMs: z.coerce.number().int().min(1000, "机器人停留时间范围不正确"),
        seatCount: z.coerce
            .number()
            .int()
            .refine((value) => value === 10 || value === 15 || value === 20, "请选择麦位数"),
        visibleRegionId: z.coerce.number().int().min(0, "区域 ID 不正确").default(0),
    })
    .refine((value) => value.maxRobotCount >= value.minRobotCount, {
        message: "机器人数量范围不正确",
        path: ["maxRobotCount"],
    })
    .refine((value) => value.luckyComboMax >= value.luckyComboMin, {
        message: "幸运礼物连击范围不正确",
        path: ["luckyComboMax"],
    })
    .refine((value) => value.luckyPauseMaxMs >= value.luckyPauseMinMs, {
        message: "幸运礼物间隔范围不正确",
        path: ["luckyPauseMaxMs"],
    })
    .refine((value) => value.robotStayMaxMs >= value.robotStayMinMs, {
        message: "机器人停留时间范围不正确",
        path: ["robotStayMaxMs"],
    })
    .refine((value) => value.robotReplaceMaxMs >= value.robotReplaceMinMs, {
        message: "机器人补位时间范围不正确",
        path: ["robotReplaceMaxMs"],
    });

export const humanRoomRobotConfigSchema = z
    .object({
        candidateRoomMaxOnline: z.coerce.number().int().min(1, "真人房间筛选人数不正确"),
        countryLimitEnabled: z.coerce.boolean().default(false),
        countryRules: z
            .array(
                z.object({
                    allowedOwnerIds: commaSeparatedTextListSchema,
                    countryCode: countryCodeSchema,
                    maxRoomCount: z.coerce.number().int().min(1, "国家进房数量不正确"),
                }),
            )
            .default([]),
        enabled: z.coerce.boolean().default(false),
        giftIds: z.array(z.string().trim().min(1)).default([]),
        luckyComboMax: z.coerce.number().int().min(1, "幸运礼物连击范围不正确"),
        luckyComboMin: z.coerce.number().int().min(1, "幸运礼物连击范围不正确"),
        luckyGiftIds: z.array(z.string().trim().min(1)).default([]),
        luckyPauseMaxMs: z.coerce.number().int().min(1000, "幸运礼物间隔范围不正确"),
        luckyPauseMinMs: z.coerce.number().int().min(1000, "幸运礼物间隔范围不正确"),
        maxGiftSenders: z.coerce.number().int().min(1, "房间送礼机器人数量不正确"),
        normalGiftIntervalMs: z.coerce.number().int().min(1000, "普通礼物频次不正确").optional(),
        normalGiftIntervalMaxMs: z.coerce.number().int().min(1000, "普通礼物间隔范围不正确"),
        normalGiftIntervalMinMs: z.coerce.number().int().min(1000, "普通礼物间隔范围不正确"),
        robotReplaceMaxMs: z.coerce.number().int().min(0, "机器人补位时间范围不正确"),
        robotReplaceMinMs: z.coerce.number().int().min(0, "机器人补位时间范围不正确"),
        robotStayMaxMs: z.coerce.number().int().min(1000, "机器人停留时间范围不正确"),
        robotStayMinMs: z.coerce.number().int().min(1000, "机器人停留时间范围不正确"),
        roomFullStopOnline: z.coerce.number().int().min(1, "真人房间停止人数不正确").optional(),
        roomTargetMaxOnline: z.coerce.number().int().min(1, "房间目标人数范围不正确"),
        roomTargetMinOnline: z.coerce.number().int().min(1, "房间目标人数范围不正确"),
        superLuckyGiftIds: z.array(z.string().trim().min(1)).default([]),
    })
    .transform((value) => ({ ...value, roomFullStopOnline: value.roomTargetMaxOnline }))
    .refine((value) => value.roomTargetMaxOnline >= value.roomTargetMinOnline, {
        message: "房间目标人数范围不正确",
        path: ["roomTargetMaxOnline"],
    })
    .refine((value) => value.roomTargetMaxOnline >= value.candidateRoomMaxOnline, {
        message: "目标人数上限不能小于筛选人数",
        path: ["roomTargetMaxOnline"],
    })
    .refine((value) => value.luckyComboMax >= value.luckyComboMin, {
        message: "幸运礼物连击范围不正确",
        path: ["luckyComboMax"],
    })
    .refine((value) => value.luckyPauseMaxMs >= value.luckyPauseMinMs, {
        message: "幸运礼物间隔范围不正确",
        path: ["luckyPauseMaxMs"],
    })
    .refine((value) => value.normalGiftIntervalMaxMs >= value.normalGiftIntervalMinMs, {
        message: "普通礼物间隔范围不正确",
        path: ["normalGiftIntervalMaxMs"],
    })
    .refine((value) => value.robotStayMaxMs >= value.robotStayMinMs, {
        message: "机器人停留时间范围不正确",
        path: ["robotStayMaxMs"],
    })
    .refine((value) => value.robotReplaceMaxMs >= value.robotReplaceMinMs, {
        message: "机器人补位时间范围不正确",
        path: ["robotReplaceMaxMs"],
    })
    .refine((value) => !value.enabled || value.giftIds.length > 0, {
        message: "启用后请选择普通礼物合集",
        path: ["giftIds"],
    })
    .refine((value) => !value.enabled || value.luckyGiftIds.length + value.superLuckyGiftIds.length > 0, {
        message: "启用后请选择幸运礼物或超级幸运礼物合集",
        path: ["luckyGiftIds"],
    })
    .superRefine((value, context) => {
        if (value.enabled && value.countryLimitEnabled && value.countryRules.length === 0) {
            context.addIssue({
                code: z.ZodIssueCode.custom,
                message: "启用国家配置后至少选择一个国家",
                path: ["countryRules"],
            });
        }
        const seen = new Set<string>();
        value.countryRules.forEach((rule, index) => {
            if (seen.has(rule.countryCode)) {
                context.addIssue({
                    code: z.ZodIssueCode.custom,
                    message: "国家不能重复",
                    path: ["countryRules", index, "countryCode"],
                });
            }
            seen.add(rule.countryCode);
        });
    });

export type RoomUpdateForm = z.infer<typeof roomUpdateSchema>;
export type RoomStatusForm = z.infer<typeof roomStatusSchema>;
export type RoomConfigForm = z.infer<typeof roomConfigSchema>;
export type RoomWhitelistForm = z.infer<typeof roomWhitelistSchema>;
export type RoomPinCreateForm = z.infer<typeof roomPinCreateSchema>;
export type RobotRoomCreateForm = z.infer<typeof robotRoomCreateSchema>;
export type HumanRoomRobotConfigForm = z.infer<typeof humanRoomRobotConfigSchema>;
