import { SetMetadata } from '@nestjs/common';

export const CACHE_KEY_METADATA = 'cache:key';
export const CACHE_TTL_METADATA = 'cache:ttl';

/**
 * Decorator to enable caching for a method
 *
 * @param key - Cache key or function to generate key from args
 * @param ttl - Time to live in seconds (optional)
 *
 * @example
 * ```typescript
 * @Cacheable('user-profile', 3600)
 * async getUserProfile(userId: string) {
 *   // This result will be cached for 1 hour
 * }
 *
 * @Cacheable((userId) => `user-${userId}`, 3600)
 * async getUserProfile(userId: string) {
 *   // Dynamic cache key based on userId
 * }
 * ```
 */
export const Cacheable = (
  key: string | ((...args: any[]) => string),
  ttl?: number,
) => {
  return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
    SetMetadata(CACHE_KEY_METADATA, key)(target, propertyKey, descriptor);
    if (ttl) {
      SetMetadata(CACHE_TTL_METADATA, ttl)(target, propertyKey, descriptor);
    }
    return descriptor;
  };
};

/**
 * Decorator to invalidate cache after method execution
 *
 * @param keyPattern - Cache key pattern to invalidate
 *
 * @example
 * ```typescript
 * @CacheEvict('user-*')
 * async updateUserProfile(userId: string, data: any) {
 *   // This will invalidate all user-* cache keys after execution
 * }
 * ```
 */
export const CacheEvict = (
  keyPattern: string | ((...args: any[]) => string),
) => {
  return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
    const originalMethod = descriptor.value;

    descriptor.value = async function (...args: any[]) {
      const result = await originalMethod.apply(this, args);

      // Get CacheService instance
      const cacheService = (this as any).cacheService;
      if (cacheService) {
        const pattern =
          typeof keyPattern === 'function' ? keyPattern(...args) : keyPattern;
        await cacheService.deletePattern(pattern);
      }

      return result;
    };

    return descriptor;
  };
};
