import { Injectable } from '@nestjs/common';
import Redis from 'ioredis';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class CacheService {
  private redis: Redis | null = null;
  private memoryCache: Record<string, any> = {};
  private isProd: boolean;

  constructor(private configService: ConfigService) {
    this.isProd = process.env.NODE_ENV === 'production';
    if (this.isProd) {
      this.redis = new Redis({
        host: this.configService.get('REDIS_HOST'),
        port: this.configService.get('REDIS_PORT'),
        password: this.configService.get('REDIS_PASSWORD'),
      });
    }
  }

  async get(key: string): Promise<any> {
    if (this.isProd && this.redis) {
      const data = await this.redis.get(key);
      return data ? JSON.parse(data) : null;
    } else {
      return this.memoryCache[key] ?? null;
    }
  }

  async set(key: string, value: any, ttl?: number): Promise<void> {
    if (this.isProd && this.redis) {
      const data = JSON.stringify(value);
      if (ttl) {
        await this.redis.setex(key, ttl, data);
      } else {
        await this.redis.set(key, data);
      }
    } else {
      this.memoryCache[key] = value;
      if (ttl) {
        setTimeout(() => delete this.memoryCache[key], ttl * 1000);
      }
    }
  }

  async del(key: string): Promise<void> {
    if (this.isProd && this.redis) {
      await this.redis.del(key);
    } else {
      delete this.memoryCache[key];
    }
  }

  async invalidatePattern(pattern: string): Promise<void> {
    if (this.isProd && this.redis) {
      const keys = await this.redis.keys(pattern);
      if (keys.length > 0) {
        await this.redis.del(keys);
      }
    } else {
      const regex = new RegExp('^' + pattern.replace('*', '.*') + '$');
      Object.keys(this.memoryCache).forEach((key) => {
        if (regex.test(key)) delete this.memoryCache[key];
      });
    }
  }

  async invalidateAll(): Promise<void> {
    if (this.isProd && this.redis) {
      await this.redis.flushall();
    } else {
      this.memoryCache = {};
    }
  }

  async invalidateUserCache(userId: string): Promise<void> {
    await this.invalidatePattern(`user:${userId}:*`);
  }

  async invalidateOrderCache(orderId: string): Promise<void> {
    await this.invalidatePattern(`order:${orderId}:*`);
  }

  async invalidateProductCache(productId: string): Promise<void> {
    await this.invalidatePattern(`product:${productId}:*`);
  }

  async invalidateInventoryCache(): Promise<void> {
    await this.invalidatePattern('inventory:*');
  }

  async getKeysByPattern(pattern: string): Promise<string[]> {
    if (this.isProd && this.redis) {
      return await this.redis.keys(pattern);
    } else {
      const regex = new RegExp('^' + pattern.replace('*', '.*') + '$');
      return Object.keys(this.memoryCache).filter(key => regex.test(key));
    }
  }
}
