import { z } from "zod";

const stageKeys = ["novice", "normal", "advanced"] as const;
const rewardSources = ["base_rtp", "activity_subsidy", "presentation_only"] as const;
const broadcastLevels = ["none", "room", "region", "global"] as const;
const ppmScale = 1_000_000;
const stageLabels: Record<(typeof stageKeys)[number], string> = {
    novice: "新手阶段",
    normal: "正常阶段",
    advanced: "高阶阶段",
};

const stageTierSchema = z.object({
    broadcastLevel: z.enum(broadcastLevels),
    enabled: z.boolean(),
    highWaterOnly: z.boolean(),
    multiplier: z.coerce.number().min(0, "倍率不能小于 0"),
    probabilityPercent: z.coerce.number().min(0, "概率不能小于 0").max(100, "概率不能超过 100%"),
    rewardSource: z.enum(rewardSources),
    tierId: z.string().optional().default(""),
});

const stageSchema = z.object({
    stage: z.enum(stageKeys),
    tiers: z.array(stageTierSchema).min(1, "阶段至少需要一个奖档"),
});

export const luckyGiftConfigFormSchema = z
    .object({
        controlBandPercent: z.coerce.number().gt(0, "波动带必须大于 0").max(5, "波动带不能超过 5%"),
        effectiveFromMs: z.coerce.number().int("生效时间必须是毫秒整数").min(0, "生效时间不能小于 0"),
        enabled: z.boolean(),
        giftPriceReference: z.coerce.number().int("参考价格必须是整数").gt(0, "参考价格必须大于 0"),
        noviceMaxEquivalentDraws: z.coerce
            .number()
            .int("新手阶段等价抽数必须是整数")
            .min(0, "新手阶段等价抽数不能小于 0"),
        normalMaxEquivalentDraws: z.coerce
            .number()
            .int("正常阶段等价抽数必须是整数")
            .min(0, "正常阶段等价抽数不能小于 0"),
        maxSinglePayout: z.coerce.number().int("单次返奖上限必须是整数").gt(0, "单次返奖上限必须大于 0"),
        userHourlyPayoutCap: z.coerce.number().int("用户小时上限必须是整数").gt(0, "用户小时上限必须大于 0"),
        userDailyPayoutCap: z.coerce.number().int("用户每日上限必须是整数").gt(0, "用户每日上限必须大于 0"),
        deviceDailyPayoutCap: z.coerce.number().int("设备每日上限必须是整数").gt(0, "设备每日上限必须大于 0"),
        roomHourlyPayoutCap: z.coerce.number().int("房间小时上限必须是整数").gt(0, "房间小时上限必须大于 0"),
        anchorDailyPayoutCap: z.coerce.number().int("主播每日上限必须是整数").gt(0, "主播每日上限必须大于 0"),
        poolId: z.string().trim().min(1, "奖池 ID 不能为空").max(96, "奖池 ID 不能超过 96 个字符"),
        poolRatePercent: z.coerce.number().min(10, "入池比例不能低于 10%").max(100, "入池比例不能超过 100%"),
        settlementWindowWager: z.coerce.number().int("结算窗口必须是整数").gt(0, "结算窗口必须大于 0"),
        stages: z.array(stageSchema).length(3, "必须配置新手、正常、高阶三个阶段"),
        targetRtpPercent: z.coerce.number().min(10, "RTP 不能低于 10%").max(99, "RTP 不能超过 99%"),
    })
    .superRefine((value, context) => {
        if (value.poolRatePercent < value.targetRtpPercent) {
            context.addIssue({ code: "custom", message: "入池比例不能低于 RTP", path: ["poolRatePercent"] });
        }
        if (value.normalMaxEquivalentDraws < value.noviceMaxEquivalentDraws) {
            context.addIssue({
                code: "custom",
                message: "正常阶段等价抽数不能小于新手阶段",
                path: ["normalMaxEquivalentDraws"],
            });
        }

        // 阶段奖档是第一步最关键的发布边界：每个阶段的概率必须闭合到 100%，
        // 且必须显式保留 0x 档，否则低价礼物会被配置成不可控的“每抽必返”体验。
        for (const stageKey of stageKeys) {
            const stageIndex = value.stages.findIndex((stage) => stage.stage === stageKey);
            if (stageIndex < 0) {
                context.addIssue({ code: "custom", message: "必须配置新手、正常、高阶三个阶段", path: ["stages"] });
                continue;
            }
            const stage = value.stages[stageIndex];
            const probabilityTotalPPM = stage.tiers.reduce((sum, tier) => {
                if (!tier.enabled) {
                    return sum;
                }
                return sum + percentToPPM(tier.probabilityPercent);
            }, 0);
            if (probabilityTotalPPM !== ppmScale) {
                context.addIssue({
                    code: "custom",
                    message: "启用奖档概率合计必须等于 100%",
                    path: ["stages", stageIndex, "tiers"],
                });
            }
            if (!stage.tiers.some((tier) => tier.enabled && tier.rewardSource === "base_rtp")) {
                context.addIssue({
                    code: "custom",
                    message: "每个阶段至少需要一个启用的基础 RTP 奖档",
                    path: ["stages", stageIndex, "tiers"],
                });
            }
            if (!stage.tiers.some((tier) => tier.enabled && Number(tier.multiplier) === 0)) {
                context.addIssue({
                    code: "custom",
                    message: "每个阶段必须显式配置 0x 未中奖档",
                    path: ["stages", stageIndex, "tiers"],
                });
            }
            const expectedRTPPPM = stage.tiers.reduce((sum, tier) => {
                if (!tier.enabled || tier.rewardSource !== "base_rtp") {
                    return sum;
                }
                return (
                    sum +
                    Math.trunc((multiplierToPPM(tier.multiplier) * percentToPPM(tier.probabilityPercent)) / ppmScale)
                );
            }, 0);
            const expectedRTP = expectedRTPPPM / 10_000;
            const lowerRTPPPM = percentToPPM(value.targetRtpPercent - value.controlBandPercent);
            const upperRTPPPM = percentToPPM(value.targetRtpPercent + value.controlBandPercent);
            if (expectedRTPPPM < lowerRTPPPM || expectedRTPPPM > upperRTPPPM) {
                context.addIssue({
                    code: "custom",
                    message: `${stageLabels[stage.stage]}期望 RTP 为 ${expectedRTP.toFixed(2)}%，必须在 ${(lowerRTPPPM / 10_000).toFixed(2)}%-${(upperRTPPPM / 10_000).toFixed(2)}% 内`,
                    path: ["stages", stageIndex, "tiers"],
                });
            }
            stage.tiers.forEach((tier, tierIndex) => {
                if (tier.enabled && Number(tier.probabilityPercent) <= 0) {
                    context.addIssue({
                        code: "custom",
                        message: "启用奖档概率必须大于 0；不想让该倍率出现请关闭奖档",
                        path: ["stages", stageIndex, "tiers", tierIndex, "probabilityPercent"],
                    });
                }
                if (tier.enabled && Number(tier.multiplier) >= 5 && !tier.highWaterOnly) {
                    context.addIssue({
                        code: "custom",
                        message: "5x 及以上奖档必须开启高水位限制",
                        path: ["stages", stageIndex, "tiers", tierIndex, "highWaterOnly"],
                    });
                }
            });
        }
    });

export type LuckyGiftConfigForm = z.infer<typeof luckyGiftConfigFormSchema>;

function percentToPPM(value: number): number {
    return Math.round(Number(value || 0) * 10_000);
}

function multiplierToPPM(value: number): number {
    return Math.round(Number(value || 0) * ppmScale);
}
