/**
 * [BE-MT002] 层级权限认证中间件
 * 负责验证用户层级权限、构建数据隔离上下文
 * AI注意: 所有需要数据隔离的路由必须使用此中间件
 */

import { Request, Response, NextFunction } from 'express';
import { logger } from '../utils/logger';
import { DataIsolationService, DataIsolationContext, HierarchyLevel } from './DataIsolationService';
import { RedisService } from './RedisService';

declare global {
  namespace Express {
    interface Request {
      isolationContext?: DataIsolationContext;
    }
  }
}

// 权限级别
export type PermissionLevel = 'TENANT' | 'DEPARTMENT' | 'SHOP' | 'OWN';

// 中间件配置
interface HierarchyAuthConfig {
  requiredLevel?: PermissionLevel;
  resourceType?: string;
  action?: 'read' | 'write' | 'delete';
  allowAdmin?: boolean;
}

export class HierarchyAuthMiddleware {
  private static readonly CONTEXT_CACHE_PREFIX = 'hierarchy_context:';
  private static readonly CONTEXT_CACHE_TTL = 1800;

  /**
   * [BE-MT002-01] 创建层级认证中间件
   */
  static create(config: HierarchyAuthConfig = {}) {
    return async (req: Request, res: Response, next: NextFunction) => {
      try {
        if (!req.user) {
          return res.status(401).json({ error: '未授权访问' });
        }

        const context = await this.buildContext(req.user.id);
        if (!context) {
          return res.status(403).json({ error: '无法构建权限上下文' });
        }

        req.isolationContext = context;

        if (config.requiredLevel) {
          const hasPermission = await this.checkPermissionLevel(
            context,
            config.requiredLevel,
            config.allowAdmin !== false
          );

          if (!hasPermission) {
            logger.warn(`[HierarchyAuth] Permission denied for user ${req.user.id}`, {
              requiredLevel: config.requiredLevel,
              userLevel: context.role,
            });
            return res.status(403).json({ error: '权限不足' });
          }
        }

        if (config.resourceType && config.action) {
          const resourceId = req.params.id || req.body.id;
          if (resourceId) {
            const hasAccess = await DataIsolationService.validateDataAccess(
              config.resourceType,
              resourceId,
              context
            );

            if (!hasAccess) {
              logger.warn(`[HierarchyAuth] Access denied to resource ${resourceId}`, {
                userId: req.user.id,
                resourceType: config.resourceType,
              });
              return res.status(403).json({ error: '无权访问此资源' });
            }
          }
        }

        next();
      } catch (error) {
        logger.error('[HierarchyAuth] Middleware error:', error);
        return res.status(500).json({ error: '权限验证失败' });
      }
    };
  }

  /**
   * [BE-MT002-02] 构建数据隔离上下文
   */
  private static async buildContext(userId: string): Promise<DataIsolationContext | null> {
    const cacheKey = `${this.CONTEXT_CACHE_PREFIX}${userId}`;
    const cached = await RedisService.get(cacheKey);
    
    if (cached) {
      return JSON.parse(cached);
    }

    const user = await this.getUserHierarchy(userId);
    if (!user) {
      return null;
    }

    const permissions = await this.getUserPermissions(userId);

    const context: DataIsolationContext = {
      tenantId: user.tenant_id,
      departmentId: user.department_id,
      shopId: user.shop_id,
      userId: user.id,
      role: user.role,
      permissions,
      hierarchyPath: user.hierarchy_path || '',
    };

    await RedisService.set(cacheKey, JSON.stringify(context), this.CONTEXT_CACHE_TTL);

    return context;
  }

  /**
   * [BE-MT002-03] 获取用户层级信息
   */
  private static async getUserHierarchy(userId: string): Promise<any> {
    const user = await require('../config/database').default('cf_user')
      .where('id', userId)
      .whereNull('deleted_at')
      .first(
        'id',
        'tenant_id',
        'department_id',
        'shop_id',
        'role',
        'hierarchy_path'
      );

    return user;
  }

  /**
   * [BE-MT002-04] 获取用户权限列表
   */
  private static async getUserPermissions(userId: string): Promise<string[]> {
    const permissions = await require('../config/database').default('cf_user_permission')
      .where('user_id', userId)
      .pluck('permission_code');

    return permissions;
  }

  /**
   * [BE-MT002-05] 检查权限级别
   */
  private static async checkPermissionLevel(
    context: DataIsolationContext,
    requiredLevel: PermissionLevel,
    allowAdmin: boolean
  ): Promise<boolean> {
    if (allowAdmin && context.role === 'ADMIN') {
      return true;
    }

    switch (requiredLevel) {
      case 'TENANT':
        return !!context.tenantId;
      
      case 'DEPARTMENT':
        return !!context.departmentId || context.role === 'MANAGER';
      
      case 'SHOP':
        return !!context.shopId || context.role === 'MANAGER' || context.role === 'OPERATOR';
      
      case 'OWN':
        return true;
      
      default:
        return false;
    }
  }

  /**
   * [BE-MT002-06] 验证层级选择器
   */
  static validateHierarchySelector(requiredLevel: PermissionLevel) {
    return async (req: Request, res: Response, next: NextFunction) => {
      try {
        if (!req.isolationContext) {
          return res.status(401).json({ error: '未授权访问' });
        }

        const { tenantId, departmentId, shopId } = req.body;

        if (requiredLevel === 'SHOP' && !shopId) {
          return res.status(400).json({ error: '必须指定店铺' });
        }

        if (requiredLevel === 'DEPARTMENT' && !departmentId) {
          return res.status(400).json({ error: '必须指定部门' });
        }

        if (tenantId && tenantId !== req.isolationContext.tenantId) {
          return res.status(403).json({ error: '无权访问此租户数据' });
        }

        if (departmentId && req.isolationContext.role !== 'ADMIN') {
          if (req.isolationContext.departmentId !== departmentId) {
            return res.status(403).json({ error: '无权访问此部门数据' });
          }
        }

        if (shopId && req.isolationContext.role !== 'ADMIN') {
          if (req.isolationContext.shopId && req.isolationContext.shopId !== shopId) {
            return res.status(403).json({ error: '无权访问此店铺数据' });
          }
        }

        next();
      } catch (error) {
        logger.error('[HierarchyAuth] Selector validation error:', error);
        return res.status(500).json({ error: '权限验证失败' });
      }
    };
  }

  /**
   * [BE-MT002-07] 清除用户上下文缓存
   */
  static async clearUserContextCache(userId: string): Promise<void> {
    await RedisService.delete(`${this.CONTEXT_CACHE_PREFIX}${userId}`);
    logger.info(`[HierarchyAuth] Cleared context cache for user ${userId}`);
  }

  /**
   * [BE-MT002-08] 数据隔离查询包装器
   */
  static withIsolation(tableName: string) {
    return async (req: Request, res: Response, next: NextFunction) => {
      try {
        if (!req.isolationContext) {
          return res.status(401).json({ error: '未授权访问' });
        }

        req.isolatedQuery = DataIsolationService.buildIsolationQuery(
          tableName,
          req.isolationContext
        );

        next();
      } catch (error) {
        logger.error('[HierarchyAuth] Isolation wrapper error:', error);
        return res.status(500).json({ error: '数据隔离失败' });
      }
    };
  }

  /**
   * [BE-MT002-09] 批量数据访问验证
   */
  static batchAccessCheck(tableName: string, idParam: string = 'ids') {
    return async (req: Request, res: Response, next: NextFunction) => {
      try {
        if (!req.isolationContext) {
          return res.status(401).json({ error: '未授权访问' });
        }

        const ids = req.body[idParam] || req.query[idParam];
        if (!ids || !Array.isArray(ids)) {
          return res.status(400).json({ error: '必须提供资源ID列表' });
        }

        const accessMap = await DataIsolationService.batchValidateAccess(
          tableName,
          ids,
          req.isolationContext
        );

        const deniedIds = ids.filter(id => !accessMap[id]);
        if (deniedIds.length > 0) {
          logger.warn(`[HierarchyAuth] Batch access denied for user ${req.user?.id}`, {
            deniedIds,
            tableName,
          });
          return res.status(403).json({
            error: '部分资源无权访问',
            deniedIds,
          });
        }

        req.accessMap = accessMap;
        next();
      } catch (error) {
        logger.error('[HierarchyAuth] Batch access check error:', error);
        return res.status(500).json({ error: '权限验证失败' });
      }
    };
  }

  /**
   * [BE-MT002-10] 角色检查中间件
   */
  static requireRole(...roles: string[]) {
    return (req: Request, res: Response, next: NextFunction) => {
      if (!req.isolationContext) {
        return res.status(401).json({ error: '未授权访问' });
      }

      if (!roles.includes(req.isolationContext.role)) {
        logger.warn(`[HierarchyAuth] Role check failed for user ${req.user?.id}`, {
          requiredRoles: roles,
          userRole: req.isolationContext.role,
        });
        return res.status(403).json({ error: '角色权限不足' });
      }

      next();
    };
  }

  /**
   * [BE-MT002-11] 权限检查中间件
   */
  static requirePermission(permission: string) {
    return (req: Request, res: Response, next: NextFunction) => {
      if (!req.isolationContext) {
        return res.status(401).json({ error: '未授权访问' });
      }

      if (req.isolationContext.role === 'ADMIN') {
        return next();
      }

      if (!req.isolationContext.permissions.includes(permission)) {
        logger.warn(`[HierarchyAuth] Permission check failed for user ${req.user?.id}`, {
          requiredPermission: permission,
          userPermissions: req.isolationContext.permissions,
        });
        return res.status(403).json({ error: '缺少必要权限' });
      }

      next();
    };
  }
}

declare global {
  namespace Express {
    interface Request {
      isolatedQuery?: any;
      accessMap?: Record<string, boolean>;
    }
  }
}
