import { NextFunction, Request, Response } from 'express';
import NodeCache from 'node-cache';
import { createClient } from 'redis';
import db from '../../config/database';
import { logger } from '../../utils/logger';

/**
 * @description API 性能网关 (Turbo Gateway)
 * 实现 L1 (Memory) / L2 (Redis) 缓存以及基于 Redis 的请求限流
 */
export class TurboGateway {
  private static l1Cache = new NodeCache({ stdTTL: 60, checkperiod: 120 }); // L1: 内存缓存，默认 60s
  private static redisClient = createClient({ url: process.env.REDIS_URL || 'redis://localhost:6379' });
  private static isRedisConnected = false;

  static async init() {
    try {
      await this.redisClient.connect();
      this.isRedisConnected = true;
      logger.info('[TurboGateway] Redis connected for L2 Cache & Rate Limiting');
    } catch (err: any) {
      logger.error(`[TurboGateway] Redis connection failed: ${err.message}`);
    }
  }

  /**
   * @description 统一缓存中间件 (L1 + L2)
   * @param {number} ttl 缓存过期时间 (秒)
   */
  static cache(ttl: number = 300) {
    return async (req: Request, res: Response, next: NextFunction) => {
      if (req.method !== 'GET') return next();

      const key = `turbo:cache:${req.originalUrl}`;

      // 1. 尝试从 L1 (Memory) 获取
      const cachedL1 = this.l1Cache.get(key);
      if (cachedL1) {
        logger.info(`[TurboGateway] L1 Cache Hit: ${key}`);
        return res.json(cachedL1);
      }

      // 2. 尝试从 L2 (Redis) 获取
      if (this.isRedisConnected) {
        try {
          const cachedL2 = await this.redisClient.get(key);
          if (cachedL2) {
            const data = JSON.parse(cachedL2);
            this.l1Cache.set(key, data, ttl / 2); // 回填 L1
            logger.info(`[TurboGateway] L2 Cache Hit: ${key}`);
            return res.json(data);
          }
        } catch (err) {
          logger.warn(`[TurboGateway] L2 Cache Error: ${err}`);
        }
      }

      // 3. 拦截 res.json 以在响应时自动存入缓存
      const originalJson = res.json.bind(res);
      res.json = (body: any) => {
        if (res.statusCode === 200) {
          this.l1Cache.set(key, body, ttl);
          if (this.isRedisConnected) {
            this.redisClient.setEx(key, ttl, JSON.stringify(body)).catch(() => {});
          }
        }
        return originalJson(body);
      };

      next();
    };
  }

  /**
   * @description 自适应限流中间件 (漏桶算法/令牌桶简化版)
   * @param {number} limit 周期内允许的最大请求数
   * @param {number} windowMs 周期时长 (毫秒)
   */
  static throttle(limit: number = 100, windowMs: number = 60000) {
    return async (req: Request, res: Response, next: NextFunction) => {
      if (!this.isRedisConnected) return next();

      const ip = req.ip || req.headers['x-forwarded-for'] || 'unknown';
      const key = `turbo:throttle:${ip}:${req.path}`;

      try {
        const current = await this.redisClient.incr(key);
        if (current === 1) {
          await this.redisClient.expire(key, Math.floor(windowMs / 1000));
        }

        if (current > limit) {
          logger.warn(`[TurboGateway] Rate limit exceeded for IP: ${ip}, Path: ${req.path}`);
          return res.status(429).json({
            success: false,
            error: 'Too many requests, please try again later.',
            retryAfter: windowMs / 1000
          });
        }
        
        next();
      } catch (err) {
        logger.error(`[TurboGateway] Throttle Error: ${err}`);
        next();
      }
    };
  }

  /**
   * [CORE_AI_15] 手动设置 L2 缓存 (用于 AI Embedding 等高价调用)
   */
  static async setL2(key: string, value: any, ttl: number = 86400) {
    if (!this.isRedisConnected) return;
    try {
      await this.redisClient.setEx(`turbo:l2:${key}`, ttl, JSON.stringify(value));
    } catch (err) {
      logger.error(`[TurboGateway] L2 Set Error: ${err}`);
    }
  }

  /**
   * [CORE_AI_15] 手动删除 L2 缓存
   */
  static async deleteL2(key: string) {
    if (!this.isRedisConnected) return;
    try {
      await this.redisClient.del(`turbo:l2:${key}`);
    } catch (err) {
      logger.error(`[TurboGateway] L2 Delete Error: ${err}`);
    }
  }

  /**
   * [CORE_AI_15] 手动获取 L2 缓存
   */
  static async getL2(key: string): Promise<any | null> {
    if (!this.isRedisConnected) return null;
    try {
      const val = await this.redisClient.get(`turbo:l2:${key}`);
      return val ? JSON.parse(val) : null;
    } catch (err) {
      logger.error(`[TurboGateway] L2 Get Error: ${err}`);
      return null;
    }
  }

  /**
   * [BIZ_GOV_07] 原子计数增加 (用于配额管理)
   */
  static async increment(key: string, windowMs: number, amount: number = 1): Promise<number> {
    if (!this.isRedisConnected) return 0;
    try {
      const fullKey = `turbo:quota:${key}`;
      const current = await this.redisClient.incrBy(fullKey, amount);
      if (current === amount) {
        await this.redisClient.expire(fullKey, Math.floor(windowMs / 1000));
      }
      return current;
    } catch (err) {
      logger.error(`[TurboGateway] Increment Error: ${err}`);
      return 0;
    }
  }

  /**
   * [CORE_DEV_09] 租户级数据预加载 (Predictive Pre-caching)
...   * @description 基于历史访问模式，预测并提前加载租户的核心业务数据到 L2 缓存
   */
  static async predictivePreload(tenantId: string): Promise<void> {
    logger.info(`[TurboGateway] Starting predictive preload for Tenant: ${tenantId}`);
    
    // 1. 预加载活跃商品指纹 (用于加速比价)
    const activeProducts = await db('cf_product').where({ tenant_id: tenantId }).limit(100);
    for (const p of activeProducts) {
      if (p.phash) {
        await this.setL2(`phash:${p.id}`, p.phash, 3600);
      }
    }

    // 2. 预加载常用配置与汇率
    await this.setL2(`config:${tenantId}`, { preloadAt: new Date() }, 3600);
    
    logger.info(`[TurboGateway] Preload completed for ${activeProducts.length} assets.`);
  }
}
