import { Request, Response, NextFunction } from 'express';
import { logger } from '../../utils/logger';

/**
 * Service Guard
 * 确保所有业务逻辑都通过 Service 层，禁止在 Controller 中直接操作数据库
 */
export class ServiceGuard {
  /**
   * 验证 Controller 是否只调用 Service 层
   * @param req 请求对象
   * @param res 响应对象
   * @param next 下一步中间件
   */
  static async validateServiceLayerUsage(req: Request, res: Response, next: NextFunction) {
    try {
      // 这里可以添加更复杂的验证逻辑
      // 例如：检查 Controller 中是否直接导入了数据库连接或 ORM
      // 或者通过 AST 分析检查代码结构
      
      // 记录请求信息
      logger.info(`[ServiceGuard] Validating service layer usage for ${req.method} ${req.path}`);
      
      // 暂时通过，后续可以添加更严格的验证
      next();
    } catch (error) {
      logger.error(`[ServiceGuard] Validation failed: ${(error as any).message}`);
      res.status(403).json({
        success: false,
        error: 'Controller must use Service layer for business logic'
      });
    }
  }

  /**
   * 装饰器：确保方法只在 Service 层调用
   */
  static OnlyService() {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
      const originalMethod = descriptor.value;
      
      descriptor.value = function (...args: any[]) {
        // 检查调用栈，确保调用来自 Service 层
        const stack = new Error().stack || '';
        const isServiceLayer = stack.includes('/services/');
        
        if (!isServiceLayer) {
          throw new Error(`Method ${propertyKey} can only be called from Service layer`);
        }
        
        return originalMethod.apply(this, args);
      };
      
      return descriptor;
    };
  }

  /**
   * 装饰器：禁止直接操作数据库
   */
  static NoDirectDatabaseAccess() {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
      const originalMethod = descriptor.value;
      
      descriptor.value = function (...args: any[]) {
        // 检查调用栈，确保不是直接操作数据库
        const stack = new Error().stack || '';
        const isRepositoryLayer = stack.includes('/repositories/');
        
        if (!isRepositoryLayer) {
          throw new Error(`Direct database access is forbidden. Use Repository layer instead.`);
        }
        
        return originalMethod.apply(this, args);
      };
      
      return descriptor;
    };
  }
}
