File size: 3,863 Bytes
3eebcd0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// 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<Tier, number> = {
  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
  }
}