import { z } from 'zod'; const snowflake = z.string().regex(/^\d{17,20}$/); export const PremiumTierSchema = z.enum(['FREE', 'PREMIUM']); export type PremiumTier = z.infer; export const PremiumFeatureKeySchema = z.enum(['tags', 'feeds', 'guildbackup']); export type PremiumFeatureKey = z.infer; export const PremiumFeaturesSchema = z.object({ tags: z.boolean(), feeds: z.boolean(), guildbackup: z.boolean() }); export type PremiumFeatures = z.infer; export const PremiumTierConfigSchema = z.object({ tier: PremiumTierSchema, maxTags: z.number().int().min(0).max(10_000), maxFeeds: z.number().int().min(0).max(10_000), maxBackups: z.number().int().min(0).max(10_000), features: PremiumFeaturesSchema }); export type PremiumTierConfig = z.infer; export const PremiumTierConfigPatchSchema = PremiumTierConfigSchema.omit({ tier: true }).partial().refine( (value) => Object.keys(value).length > 0, { message: 'At least one field is required' } ); export type PremiumTierConfigPatch = z.infer; export const DEFAULT_PREMIUM_TIER_CONFIGS: Record = { FREE: { tier: 'FREE', maxTags: 15, maxFeeds: 3, maxBackups: 2, features: { tags: true, feeds: true, guildbackup: true } }, PREMIUM: { tier: 'PREMIUM', maxTags: 100, maxFeeds: 25, maxBackups: 25, features: { tags: true, feeds: true, guildbackup: true } } }; export const GuildPremiumAssignSchema = z.object({ guildId: snowflake, tier: PremiumTierSchema, note: z.string().max(500).nullable().optional(), expiresAt: z.string().datetime().nullable().optional() }); export type GuildPremiumAssign = z.infer; export const UserPremiumAssignSchema = z.object({ userId: snowflake, tier: PremiumTierSchema, note: z.string().max(500).nullable().optional(), expiresAt: z.string().datetime().nullable().optional() }); export type UserPremiumAssign = z.infer; export const PremiumLimitResourceSchema = z.enum(['tags', 'feeds', 'backups']); export type PremiumLimitResource = z.infer; export function limitKeyForResource(resource: PremiumLimitResource): 'maxTags' | 'maxFeeds' | 'maxBackups' { if (resource === 'tags') return 'maxTags'; if (resource === 'feeds') return 'maxFeeds'; return 'maxBackups'; } export function featureKeyForResource(resource: PremiumLimitResource): PremiumFeatureKey { if (resource === 'backups') return 'guildbackup'; return resource; } export function parsePremiumFeatures(raw: unknown): PremiumFeatures { const parsed = PremiumFeaturesSchema.safeParse(raw); if (parsed.success) { return parsed.data; } return { tags: true, feeds: true, guildbackup: true }; } export function isAssignmentActive(expiresAt: Date | string | null | undefined, now = new Date()): boolean { if (!expiresAt) { return true; } const date = typeof expiresAt === 'string' ? new Date(expiresAt) : expiresAt; return date.getTime() > now.getTime(); }