import { z } from "zod";

export const appUserUpdateSchema = z.object({
    avatar: z.string().trim().max(512, "头像不能超过 512 个字符").optional().default(""),
    gender: z.string().trim().max(32, "性别不能超过 32 个字符").optional().default(""),
    username: z.string().trim().max(64, "用户名称不能超过 64 个字符").optional().default(""),
});

export const appUserCountrySchema = z.object({
    country: z.string().trim().min(2, "请选择国家").max(16, "国家码不能超过 16 个字符"),
});

export const appUserPasswordSchema = z.object({
    password: z.string().trim().min(6, "密码至少 6 位").max(128, "密码不能超过 128 个字符"),
});

const temporaryLevelTrackSchema = z.object({
    durationDays: z.string().trim().optional().default("7"),
    enabled: z.boolean().optional().default(false),
    level: z.string().trim().optional().default(""),
});

// 财富和魅力必须作为一次命令提交；表单在送出前校验双轨边界（产品等级上限为 100），后端继续负责真实等级、规则启用状态和事务原子性。
export const appUserLevelAdjustmentSchema = z
    .object({
        charm: temporaryLevelTrackSchema,
        reason: z.string().trim().max(128, "调整原因不能超过 128 个字符").optional().default(""),
        wealth: temporaryLevelTrackSchema,
    })
    .superRefine((value, context) => {
        const enabledTracks = [
            ["wealth", value.wealth],
            ["charm", value.charm],
        ] as const;
        if (!enabledTracks.some(([, track]) => track.enabled)) {
            context.addIssue({ code: "custom", message: "至少选择一个等级轨道", path: ["wealth", "enabled"] });
            return;
        }
        enabledTracks.forEach(([name, track]) => {
            if (!track.enabled) {
                return;
            }
            const level = Number(track.level);
            if (!Number.isInteger(level) || level < 1 || level > 100) {
                context.addIssue({ code: "custom", message: "目标等级必须是 1 到 100 的整数", path: [name, "level"] });
            }
            const durationDays = Number(track.durationDays);
            if (!Number.isInteger(durationDays) || durationDays < 1 || durationDays > 36500) {
                context.addIssue({
                    code: "custom",
                    message: "有效天数必须是 1 到 36500 的整数",
                    path: [name, "durationDays"],
                });
            }
        });
    });

// expires_at_ms=0 仅由“永久”模式产生；指定截止时间必须在浏览器当前时刻之后，服务端仍以 UTC 再次校验。
export const appUserBanSchema = z
    .object({
        expiresAtLocal: z.string().trim().optional().default(""),
        mode: z.enum(["permanent", "timed"], "请选择封禁期限"),
        reason: z.string().trim().max(512, "封禁原因不能超过 512 个字符").optional().default(""),
    })
    .superRefine((value, context) => {
        if (value.mode !== "timed") {
            return;
        }
        const expiresAtMs = new Date(value.expiresAtLocal).getTime();
        if (!value.expiresAtLocal || !Number.isFinite(expiresAtMs) || expiresAtMs <= Date.now()) {
            context.addIssue({ code: "custom", message: "截止时间必须晚于当前时间", path: ["expiresAtLocal"] });
        }
    });

const prettyRuleValues = [
    "aa",
    "aaa",
    "aaaa",
    "aaaaa",
    "aaaaaa",
    "aaaaaaa",
    "aabb",
    "aabbcc",
    "aabbccdd",
    "abab",
    "ababab",
    "abba",
    "abcba",
    "abccba",
    "aaab",
    "aaaab",
    "aaaaab",
    "aaabbb",
    "aaaabbbb",
    "abc",
    "abcd",
    "abcde",
    "abcdef",
    "cba",
    "dcba",
    "edcba",
    "fedcba",
    "abcabc",
    "date_yyyymmdd",
    "date_yymmdd",
    "love",
    "custom_values",
    "custom_pattern",
] as const;

// 靓号池只配置等级区间和生成规则，等级上下限在表单层先做顺序校验，后端仍会再次校验权限和状态。
export const prettyDisplayIDPoolSchema = z
    .object({
        levelTrack: z.enum(["wealth", "game", "charm"], "请选择等级轨道"),
        maxLevel: z.coerce.number().int("最高等级必须是整数").min(0, "最高等级不能小于 0"),
        minLevel: z.coerce.number().int("最低等级必须是整数").min(0, "最低等级不能小于 0"),
        name: z.string().trim().min(1, "请输入靓号池名称").max(128, "靓号池名称不能超过 128 个字符"),
        ruleConfigJson: z.string().trim().max(4000, "规则配置不能超过 4000 个字符").optional().default(""),
        ruleType: z.enum(prettyRuleValues, "请选择生成规则"),
        sortOrder: z.coerce.number().int("排序必须是整数").min(0, "排序不能小于 0").optional().default(0),
        status: z.enum(["active", "disabled"], "请选择状态"),
    })
    .refine((value) => value.maxLevel >= value.minLevel, {
        message: "最高等级不能小于最低等级",
        path: ["maxLevel"],
    });

// 批量生成支持市面常见靓号模式，单次最多 1000 个，避免一次生成把候选空间和数据库锁时间放大。
export const prettyDisplayIDGenerateSchema = z.object({
    count: z.coerce.number().int("生成数量必须是整数").min(1, "生成数量至少 1 个").max(1000, "单次最多生成 1000 个"),
    poolId: z.string().trim().min(1, "请选择靓号池"),
    ruleConfigJson: z.string().trim().max(4000, "规则配置不能超过 4000 个字符").optional().default(""),
    ruleType: z.enum(prettyRuleValues, "请选择生成规则"),
});

// 靓号展示内容必须原样支持任意 Unicode 字符，不能以字母数字正则过滤字体字形、表情或符号；仅去除首尾空白、限制长度并拦截控制字符，服务端继续负责唯一性和持久化安全校验。
export const prettyDisplayIDGrantSchema = z.object({
    displayUserId: z
        .string()
        .trim()
        .min(1, "请输入靓号内容")
        // String.length 会把补充平面 Unicode 字符计为两个 UTF-16 单元，必须按 code point 计数，才能和服务端的 rune 上限一致。
        .refine((value) => Array.from(value).length <= 64, "靓号不能超过 64 个字符")
        // 控制字符不是展示字形，保留会破坏列表、日志和协议载荷；符号、emoji 和格式化字形仍可通过。
        .refine((value) => !/\p{Cc}/u.test(value), "靓号不能包含控制字符"),
    durationDays: z
        .string()
        .trim()
        .optional()
        .default("")
        .refine((value) => {
            if (!value) {
                return true;
            }
            const days = Number(value);
            return Number.isInteger(days) && days >= 0 && days <= 36500;
        }, "有效天数必须是 0 到 36500 的整数"),
    reason: z.string().trim().max(64, "原因不能超过 64 个字符").optional().default(""),
    targetUserId: z.string().trim().min(1, "请输入用户 ID 或短 ID").max(64, "用户 ID 或短 ID 不能超过 64 个字符"),
});

// 状态变更只暴露未占用号码的 available/disabled/reserved，assigned 号码必须通过释放或覆盖链路改变。
export const prettyDisplayIDStatusSchema = z.object({
    prettyId: z.string().trim().min(1, "请选择靓号"),
    reason: z.string().trim().max(64, "原因不能超过 64 个字符").optional().default(""),
    status: z.enum(["available", "disabled", "reserved"], "请选择状态"),
});

export type AppUserUpdateForm = z.infer<typeof appUserUpdateSchema>;
export type AppUserCountryForm = z.infer<typeof appUserCountrySchema>;
export type AppUserPasswordForm = z.infer<typeof appUserPasswordSchema>;
export type AppUserLevelAdjustmentForm = z.infer<typeof appUserLevelAdjustmentSchema>;
export type AppUserBanForm = z.infer<typeof appUserBanSchema>;
export type PrettyDisplayIDPoolForm = z.infer<typeof prettyDisplayIDPoolSchema>;
export type PrettyDisplayIDGenerateForm = z.infer<typeof prettyDisplayIDGenerateSchema>;
export type PrettyDisplayIDGrantForm = z.infer<typeof prettyDisplayIDGrantSchema>;
export type PrettyDisplayIDStatusForm = z.infer<typeof prettyDisplayIDStatusSchema>;
