// Sistema de créditos por tier - PERMANENTES (se resetean solo si suben de nivel) // Los límites no se resetean mensualmente, son parte de lo que pagan // Se resetean SOLO si el cliente actualiza su suscripción a un tier superior export const TIER_LIMITS = { free: { influencers_per_month: 2, stories_per_month: 3, images_per_month: 5, videos_per_month: 1, content_per_month: 10, }, basic: { influencers_per_month: 10, stories_per_month: 15, images_per_month: 30, videos_per_month: 5, content_per_month: 50, }, premium: { influencers_per_month: 50, stories_per_month: 60, images_per_month: 150, videos_per_month: 20, content_per_month: 300, }, pro: { influencers_per_month: 500, stories_per_month: 999, images_per_month: 999, videos_per_month: 999, content_per_month: 999, }, }; export type Tier = keyof typeof TIER_LIMITS; export type ResourceType = keyof (typeof TIER_LIMITS)["free"]; // Ranking de tiers para comparaciones export const TIER_RANK: Record = { free: 0, basic: 1, premium: 2, pro: 3, }; // Comprueba si el usuario con `userTier` puede suscribirse a una suscripción de `subTier`. // Regla: el usuario solo puede crear suscripciones con un tier <= su propio tier. export function isSubscriptionTierAllowed(userTier: Tier | string, subTier: Tier | string) { const u = (userTier as Tier) in TIER_RANK ? (userTier as Tier) : (userTier as Tier); const s = (subTier as Tier) in TIER_RANK ? (subTier as Tier) : (subTier as Tier); const ur = TIER_RANK[u as Tier] ?? 0; const sr = TIER_RANK[s as Tier] ?? 0; return ur >= sr; } // Validar si usuario puede hacer la acción // Los límites son PERMANENTES para el tier contratado // Se resetean solo si el usuario sube a un tier superior o solicita un reset manual export async function validateUserCredit( db: any, userId: string, resourceType: ResourceType, tier: Tier ): Promise<{ allowed: boolean; reason?: string; remaining?: number }> { const limit = TIER_LIMITS[tier][resourceType]; // Contar TODOS los recursos creados (sin límite de fecha) // Son permanentes para este tier de suscripción let used = 0; try { if (resourceType === "influencers_per_month") { used = await db.aIInfluencer.count({ where: { // Sin filtro de fecha - son permanentes }, }); } else if (resourceType === "stories_per_month") { used = await db.story.count({ where: { // Sin filtro de fecha - son permanentes }, }); } else if (resourceType === "images_per_month") { used = await db.content.count({ where: { type: "image", // Sin filtro de fecha - son permanentes }, }); } else if (resourceType === "videos_per_month") { used = await db.content.count({ where: { type: "video", // Sin filtro de fecha - son permanentes }, }); } else if (resourceType === "content_per_month") { used = await db.content.count({ where: { // Sin filtro de fecha - son permanentes }, }); } } catch { // Si hay error, permitir (más seguro que bloquear) used = 0; } const remaining = Math.max(0, limit - used); return { allowed: remaining > 0, reason: remaining === 0 ? `Límite de ${resourceType} alcanzado (${limit}). Necesitas subir a un tier superior.` : undefined, remaining, }; } // Log de uso (opcional, para futuro tracking) export async function logResourceUsage( db: any, userId: string, resourceType: ResourceType, resourceId: string ) { try { // Implementar cuando sea necesario // await db.resourceUsage.create({...}) } catch { // Ignorar errores de logging } }