import { createClient } from 'redis';
import log4js from 'log4js';
import dotenv from 'dotenv';

dotenv.config();

const LOG_LEVEL = process.env.LOG_LEVEL || 'info';
const REDIS_URL = process.env.REDIS_URL;
const REDIS_HOST = process.env.REDIS_HOST || '127.0.0.1';
const REDIS_PORT = process.env.REDIS_PORT || 6379;
const REDIS_PASSWORD = process.env.REDIS_PASSWORD || undefined;

const logger = log4js.getLogger('Redis');
logger.level = LOG_LEVEL;

class RedisServer {
  constructor() {
    const url = REDIS_URL || `redis://${REDIS_HOST}:${REDIS_PORT}`;

    this.client = createClient({
      url,
      password: REDIS_PASSWORD,
    });

    this.client.on('error', (err) => {
      logger.error('Redis Client Error', err);
    });

    this.connected = false;
  }

  async connect() {
    if (this.connected) return;
    logger.info('Connecting to Redis...');
    await this.client.connect();
    this.connected = true;
    logger.info('Connected to Redis');
  }

  async setKey(key, value, ttlSeconds) {
    await this.connect();
    const payload = typeof value === 'string' ? value : JSON.stringify(value);
    if (ttlSeconds) {
      await this.client.set(key, payload, { EX: ttlSeconds });
    } else {
      await this.client.set(key, payload);
    }
  }

  async getKey(key) {
    await this.connect();
    const value = await this.client.get(key);
    if (value == null) return null;
    try {
      return JSON.parse(value);
    } catch {
      return value;
    }
  }

  async deleteKey(key) {
    await this.connect();
    await this.client.del(key);
  }

  async getKeysByPattern(pattern) {
    await this.connect();
    const keys = [];
    let cursor = '0';
    do {
      const result = await this.client.scan(cursor, {
        MATCH: pattern,
        COUNT: 100,
      });
      cursor = result.cursor;
      keys.push(...result.keys);
    } while (cursor !== '0');
    return keys;
  }
}

const redisServer = new RedisServer();

export { RedisServer, redisServer };
