/**
 * [BE-MT001] 数据隔离服务
 * 负责多租户数据隔离、层级权限控制、数据过滤
 * AI注意: 所有数据查询必须通过此服务进行隔离过滤
 */

import db from '../config/database';
import { logger } from '../utils/logger';
import { RedisService } from './RedisService';

// 层级类型
export type HierarchyLevel = 'TENANT' | 'DEPARTMENT' | 'SHOP';

// 层级节点
export interface HierarchyNode {
  id: string;
  type: HierarchyLevel;
  parentId: string | null;
  name: string;
  path: string;
  depth: number;
  children?: HierarchyNode[];
}

// 数据隔离上下文
export interface DataIsolationContext {
  tenantId: string;
  departmentId?: string;
  shopId?: string;
  userId: string;
  role: string;
  permissions: string[];
  hierarchyPath: string;
}

// 数据隔离规则
export interface IsolationRule {
  tableName: string;
  tenantColumn: string;
  departmentColumn?: string;
  shopColumn?: string;
  softDelete?: boolean;
}

// 预定义的隔离规则
const ISOLATION_RULES: Record<string, IsolationRule> = {
  cf_product: {
    tableName: 'cf_product',
    tenantColumn: 'tenant_id',
    shopColumn: 'shop_id',
    softDelete: true,
  },
  cf_order: {
    tableName: 'cf_order',
    tenantColumn: 'tenant_id',
    shopColumn: 'shop_id',
    softDelete: true,
  },
  cf_customer: {
    tableName: 'cf_customer',
    tenantColumn: 'tenant_id',
    shopColumn: 'shop_id',
    softDelete: true,
  },
  cf_inventory: {
    tableName: 'cf_inventory',
    tenantColumn: 'tenant_id',
    shopColumn: 'shop_id',
    softDelete: true,
  },
  cf_settlement: {
    tableName: 'cf_settlement',
    tenantColumn: 'tenant_id',
    departmentColumn: 'department_id',
    shopColumn: 'shop_id',
    softDelete: false,
  },
  cf_user: {
    tableName: 'cf_user',
    tenantColumn: 'tenant_id',
    departmentColumn: 'department_id',
    softDelete: false,
  },
  cf_department: {
    tableName: 'cf_department',
    tenantColumn: 'tenant_id',
    softDelete: false,
  },
  cf_shop: {
    tableName: 'cf_shop',
    tenantColumn: 'tenant_id',
    departmentColumn: 'department_id',
    softDelete: false,
  },
  cf_merchant_metrics: {
    tableName: 'cf_merchant_metrics',
    tenantColumn: 'tenant_id',
    softDelete: false,
  },
  cf_ai_decision_logs: {
    tableName: 'cf_ai_decision_logs',
    tenantColumn: 'tenant_id',
    shopColumn: 'shop_id',
    softDelete: false,
  },
};

export class DataIsolationService {
  private static readonly CACHE_PREFIX = 'data_isolation:';
  private static readonly CACHE_TTL = 3600;

  /**
   * [BE-MT001-01] 构建数据隔离查询条件
   */
  static buildIsolationQuery(
    tableName: string,
    context: DataIsolationContext,
    queryBuilder?: any
  ): any {
    const rule = ISOLATION_RULES[tableName];
    if (!rule) {
      logger.warn(`[DataIsolation] No isolation rule found for table: ${tableName}`);
      return queryBuilder || db(tableName);
    }

    let query = queryBuilder || db(tableName);

    // 租户隔离（必须）
    query = query.where(rule.tenantColumn, context.tenantId);

    // 根据角色和层级进行更细粒度的隔离
    if (context.role !== 'ADMIN') {
      // 非管理员需要进一步隔离
      if (context.shopId && rule.shopColumn) {
        // 店铺级别用户只能看到自己店铺的数据
        query = query.where(rule.shopColumn, context.shopId);
      } else if (context.departmentId && rule.departmentColumn) {
        // 部门级别用户只能看到自己部门的数据
        query = query.where(rule.departmentColumn, context.departmentId);
      }
    }

    // 软删除过滤
    if (rule.softDelete) {
      query = query.whereNull('deleted_at');
    }

    logger.debug(`[DataIsolation] Built isolation query for ${tableName}`, {
      tenantId: context.tenantId,
      departmentId: context.departmentId,
      shopId: context.shopId,
      role: context.role,
    });

    return query;
  }

  /**
   * [BE-MT001-02] 验证数据访问权限
   */
  static async validateDataAccess(
    tableName: string,
    recordId: string,
    context: DataIsolationContext
  ): Promise<boolean> {
    const rule = ISOLATION_RULES[tableName];
    if (!rule) {
      return true;
    }

    const cacheKey = `${this.CACHE_PREFIX}access:${tableName}:${recordId}:${context.userId}`;
    const cached = await RedisService.get(cacheKey);
    if (cached !== null) {
      return cached === 'true';
    }

    const record = await db(tableName)
      .where('id', recordId)
      .first();

    if (!record) {
      return false;
    }

    let hasAccess = false;

    // 检查租户隔离
    if (record[rule.tenantColumn] !== context.tenantId) {
      hasAccess = false;
    }
    // 管理员有完全访问权限
    else if (context.role === 'ADMIN') {
      hasAccess = true;
    }
    // 检查店铺隔离
    else if (context.shopId && rule.shopColumn) {
      hasAccess = record[rule.shopColumn] === context.shopId;
    }
    // 检查部门隔离
    else if (context.departmentId && rule.departmentColumn) {
      hasAccess = record[rule.departmentColumn] === context.departmentId;
    }
    // 仅有租户隔离
    else {
      hasAccess = true;
    }

    await RedisService.set(cacheKey, String(hasAccess), this.CACHE_TTL);

    return hasAccess;
  }

  /**
   * [BE-MT001-03] 获取用户可见的层级节点列表
   */
  static async getVisibleNodes(
    context: DataIsolationContext,
    nodeType?: HierarchyLevel
  ): Promise<HierarchyNode[]> {
    const cacheKey = `${this.CACHE_PREFIX}nodes:${context.tenantId}:${context.userId}:${nodeType || 'all'}`;
    const cached = await RedisService.get(cacheKey);
    if (cached) {
      return JSON.parse(cached);
    }

    let nodes: HierarchyNode[] = [];

    if (context.role === 'ADMIN') {
      // 管理员可以看到租户下所有节点
      if (!nodeType || nodeType === 'DEPARTMENT') {
        const departments = await db('cf_department')
          .where('tenant_id', context.tenantId)
          .whereNull('deleted_at')
          .select('id', 'name', 'parent_id', 'path', 'depth');
        
        nodes.push(...departments.map(d => ({
          id: d.id,
          type: 'DEPARTMENT' as HierarchyLevel,
          parentId: d.parent_id,
          name: d.name,
          path: d.path,
          depth: d.depth,
        })));
      }

      if (!nodeType || nodeType === 'SHOP') {
        const shops = await db('cf_shop')
          .where('tenant_id', context.tenantId)
          .whereNull('deleted_at')
          .select('id', 'name', 'department_id as parentId', 'path', 'depth');
        
        nodes.push(...shops.map(s => ({
          id: s.id,
          type: 'SHOP' as HierarchyLevel,
          parentId: s.parentId,
          name: s.name,
          path: s.path,
          depth: s.depth,
        })));
      }
    } else if (context.shopId) {
      // 店铺用户只能看到自己的店铺
      const shop = await db('cf_shop')
        .where('id', context.shopId)
        .where('tenant_id', context.tenantId)
        .first();
      
      if (shop) {
        nodes.push({
          id: shop.id,
          type: 'SHOP',
          parentId: shop.department_id,
          name: shop.name,
          path: shop.path,
          depth: shop.depth,
        });
      }
    } else if (context.departmentId) {
      // 部门用户可以看到部门及其下属店铺
      if (!nodeType || nodeType === 'DEPARTMENT') {
        const department = await db('cf_department')
          .where('id', context.departmentId)
          .where('tenant_id', context.tenantId)
          .first();
        
        if (department) {
          nodes.push({
            id: department.id,
            type: 'DEPARTMENT',
            parentId: department.parent_id,
            name: department.name,
            path: department.path,
            depth: department.depth,
          });
        }
      }

      if (!nodeType || nodeType === 'SHOP') {
        const shops = await db('cf_shop')
          .where('department_id', context.departmentId)
          .where('tenant_id', context.tenantId)
          .whereNull('deleted_at')
          .select('id', 'name', 'department_id as parentId', 'path', 'depth');
        
        nodes.push(...shops.map(s => ({
          id: s.id,
          type: 'SHOP' as HierarchyLevel,
          parentId: s.parentId,
          name: s.name,
          path: s.path,
          depth: s.depth,
        })));
      }
    }

    await RedisService.set(cacheKey, JSON.stringify(nodes), this.CACHE_TTL);

    return nodes;
  }

  /**
   * [BE-MT001-04] 构建层级树结构
   */
  static async buildHierarchyTree(context: DataIsolationContext): Promise<HierarchyNode[]> {
    const nodes = await this.getVisibleNodes(context);
    
    const nodeMap = new Map<string, HierarchyNode>();
    const rootNodes: HierarchyNode[] = [];

    nodes.forEach(node => {
      nodeMap.set(node.id, { ...node, children: [] });
    });

    nodeMap.forEach(node => {
      if (node.parentId && nodeMap.has(node.parentId)) {
        const parent = nodeMap.get(node.parentId)!;
        parent.children = parent.children || [];
        parent.children.push(node);
      } else {
        rootNodes.push(node);
      }
    });

    return rootNodes;
  }

  /**
   * [BE-MT001-05] 获取层级路径
   */
  static async getHierarchyPath(
    nodeId: string,
    nodeType: HierarchyLevel
  ): Promise<string> {
    const tableName = nodeType === 'SHOP' ? 'cf_shop' : 'cf_department';
    const record = await db(tableName)
      .where('id', nodeId)
      .first('path');

    return record?.path || '';
  }

  /**
   * [BE-MT001-06] 验证层级关系
   */
  static async validateHierarchy(
    parentId: string | null,
    parentType: HierarchyLevel,
    childType: HierarchyLevel,
    tenantId: string
  ): Promise<{ valid: boolean; error?: string }> {
    if (!parentId) {
      if (childType === 'DEPARTMENT') {
        return { valid: true };
      }
      return { valid: false, error: '店铺必须有父部门' };
    }

    const parentTable = parentType === 'SHOP' ? 'cf_shop' : 'cf_department';
    const parent = await db(parentTable)
      .where('id', parentId)
      .where('tenant_id', tenantId)
      .first();

    if (!parent) {
      return { valid: false, error: '父节点不存在' };
    }

    if (childType === 'SHOP' && parentType !== 'DEPARTMENT') {
      return { valid: false, error: '店铺只能属于部门' };
    }

    if (childType === 'DEPARTMENT' && parentType === 'SHOP') {
      return { valid: false, error: '部门不能属于店铺' };
    }

    return { valid: true };
  }

  /**
   * [BE-MT001-07] 批量检查数据访问权限
   */
  static async batchValidateAccess(
    tableName: string,
    recordIds: string[],
    context: DataIsolationContext
  ): Promise<Record<string, boolean>> {
    const rule = ISOLATION_RULES[tableName];
    if (!rule) {
      return recordIds.reduce((acc, id) => ({ ...acc, [id]: true }), {});
    }

    const records = await db(tableName)
      .whereIn('id', recordIds)
      .select('id', rule.tenantColumn, rule.shopColumn, rule.departmentColumn);

    const result: Record<string, boolean> = {};

    records.forEach(record => {
      let hasAccess = false;

      if (record[rule.tenantColumn] !== context.tenantId) {
        hasAccess = false;
      } else if (context.role === 'ADMIN') {
        hasAccess = true;
      } else if (context.shopId && rule.shopColumn) {
        hasAccess = record[rule.shopColumn] === context.shopId;
      } else if (context.departmentId && rule.departmentColumn) {
        hasAccess = record[rule.departmentColumn] === context.departmentId;
      } else {
        hasAccess = true;
      }

      result[record.id] = hasAccess;
    });

    recordIds.forEach(id => {
      if (!(id in result)) {
        result[id] = false;
      }
    });

    return result;
  }

  /**
   * [BE-MT001-08] 清除隔离缓存
   */
  static async clearIsolationCache(
    tenantId: string,
    userId?: string
  ): Promise<void> {
    const pattern = userId
      ? `${this.CACHE_PREFIX}*:${tenantId}:${userId}:*`
      : `${this.CACHE_PREFIX}*:${tenantId}:*`;

    await RedisService.deletePattern(pattern);
    logger.info(`[DataIsolation] Cleared cache for tenant ${tenantId}`);
  }

  /**
   * [BE-MT001-09] 获取隔离规则
   */
  static getIsolationRule(tableName: string): IsolationRule | undefined {
    return ISOLATION_RULES[tableName];
  }

  /**
   * [BE-MT001-10] 注册自定义隔离规则
   */
  static registerIsolationRule(rule: IsolationRule): void {
    ISOLATION_RULES[rule.tableName] = rule;
    logger.info(`[DataIsolation] Registered isolation rule for ${rule.tableName}`);
  }
}
