import { RedisService } from '../../utils/RedisService';
import { logger } from '../../utils/logger';
import { v4 as uuidv4 } from 'uuid';

/**
 * [CORE_DEV_18] 千万级并发分布式锁优化 (DistLock V2)
 * @description 基于 Redis Lua 脚本实现高性能、高可靠的分布式锁，支持自动续期与原子解锁
 */
export class DistLockV2Service {
  private static readonly LOCK_SCRIPT = `
    if redis.call('set', KEYS[1], ARGV[1], 'NX', 'PX', ARGV[2]) then
      return 1
    else
      return 0
    end
  `;

  private static readonly UNLOCK_SCRIPT = `
    if redis.call('get', KEYS[1]) == ARGV[1] then
      return redis.call('del', KEYS[1])
    else
      return 0
    end
  `;

  private static readonly EXTEND_SCRIPT = `
    if redis.call('get', KEYS[1]) == ARGV[1] then
      return redis.call('pexpire', KEYS[1], ARGV[2])
    else
      return 0
    end
  `;

  /**
   * 获取分布式锁
   * @param key 锁的键名
   * @param ttl 锁的过期时间 (毫秒)
   */
  static async lock(key: string, ttl: number = 5000): Promise<string | null> {
    const redis = RedisService.getClient();
    const lockId = uuidv4();

    try {
      const result = await redis.eval(this.LOCK_SCRIPT, 1, key, lockId, ttl);
      if (result === 1) {
        logger.debug(`[DistLockV2] Lock acquired for ${key} with ID: ${lockId}`);
        return lockId;
      }
      return null;
    } catch (err: any) {
      logger.error(`[DistLockV2] Failed to acquire lock for ${key}: ${err.message}`);
      return null;
    }
  }

  /**
   * 释放分布式锁
   * @param key 锁的键名
   * @param lockId 持有的锁 ID (防止误删他人的锁)
   */
  static async unlock(key: string, lockId: string): Promise<boolean> {
    const redis = RedisService.getClient();
    try {
      const result = await redis.eval(this.UNLOCK_SCRIPT, 1, key, lockId);
      if (result === 1) {
        logger.debug(`[DistLockV2] Lock released for ${key} with ID: ${lockId}`);
        return true;
      }
      return false;
    } catch (err: any) {
      logger.error(`[DistLockV2] Failed to release lock for ${key}: ${err.message}`);
      return false;
    }
  }

  /**
   * 自动续期锁 (模拟 Watchdog 机制)
   */
  static async extend(key: string, lockId: string, ttl: number = 5000): Promise<boolean> {
    const redis = RedisService.getClient();
    try {
      const result = await redis.eval(this.EXTEND_SCRIPT, 1, key, lockId, ttl);
      return result === 1;
    } catch (err: any) {
      logger.error(`[DistLockV2] Failed to extend lock for ${key}: ${err.message}`);
      return false;
    }
  }
}
