/**
 * [BE-MT002] 层级管理服务
 * 负责商户→部门→店铺三层层级结构的管理
 * AI注意: 所有层级操作必须通过此服务进行
 */

import db from '../config/database';
import { logger } from '../utils/logger';
import { EventBusService } from './EventBusService';
import { RedisService } from './RedisService';
import { DataIsolationService, HierarchyLevel, HierarchyNode, DataIsolationContext } from './DataIsolationService';

// 部门接口
export interface Department {
  id: string;
  tenant_id: string;
  name: string;
  parent_id: string | null;
  path: string;
  depth: number;
  manager_id?: string;
  status: 'ACTIVE' | 'INACTIVE';
  created_at: Date;
  updated_at: Date;
}

// 店铺接口
export interface Shop {
  id: string;
  tenant_id: string;
  department_id: string;
  name: string;
  platform: string;
  shop_code: string;
  path: string;
  depth: number;
  status: 'ACTIVE' | 'INACTIVE' | 'SUSPENDED';
  created_at: Date;
  updated_at: Date;
}

// 层级统计
export interface HierarchyStats {
  totalDepartments: number;
  totalShops: number;
  activeShops: number;
  inactiveShops: number;
  maxDepth: number;
}

export class HierarchyService {
  private static readonly CACHE_PREFIX = 'hierarchy:';
  private static readonly CACHE_TTL = 3600;

  /**
   * [BE-MT002-01] 初始化租户层级结构
   */
  static async initializeTenantHierarchy(tenantId: string): Promise<void> {
    const exists = await db('cf_department')
      .where('tenant_id', tenantId)
      .first();

    if (exists) {
      logger.info(`[Hierarchy] Tenant ${tenantId} hierarchy already initialized`);
      return;
    }

    const defaultDepartment: Partial<Department> = {
      id: `DEPT-${tenantId}-DEFAULT`,
      tenant_id: tenantId,
      name: '默认部门',
      parent_id: null,
      path: `/DEPT-${tenantId}-DEFAULT`,
      depth: 1,
      status: 'ACTIVE',
      created_at: new Date(),
      updated_at: new Date(),
    };

    await db('cf_department').insert(defaultDepartment);

    await EventBusService.publish('hierarchy.department.created', {
      departmentId: defaultDepartment.id,
      tenantId,
      isDefault: true,
      timestamp: new Date(),
    });

    logger.info(`[Hierarchy] Initialized default department for tenant ${tenantId}`);
  }

  /**
   * [BE-MT002-02] 创建部门
   */
  static async createDepartment(
    tenantId: string,
    name: string,
    parentId: string | null = null,
    managerId?: string
  ): Promise<Department> {
    let depth = 1;
    let parentPath = '';

    if (parentId) {
      const parent = await db('cf_department')
        .where('id', parentId)
        .where('tenant_id', tenantId)
        .first();

      if (!parent) {
        throw new Error('父部门不存在');
      }

      depth = parent.depth + 1;
      parentPath = parent.path;
    }

    const id = `DEPT-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    const path = `${parentPath}/${id}`;

    const department: Partial<Department> = {
      id,
      tenant_id: tenantId,
      name,
      parent_id: parentId,
      path,
      depth,
      manager_id: managerId,
      status: 'ACTIVE',
      created_at: new Date(),
      updated_at: new Date(),
    };

    await db('cf_department').insert(department);

    await this.clearHierarchyCache(tenantId);

    await EventBusService.publish('hierarchy.department.created', {
      departmentId: id,
      tenantId,
      parentId,
      timestamp: new Date(),
    });

    logger.info(`[Hierarchy] Created department ${id} for tenant ${tenantId}`);

    return department as Department;
  }

  /**
   * [BE-MT002-03] 更新部门
   */
  static async updateDepartment(
    departmentId: string,
    tenantId: string,
    updates: Partial<Department>
  ): Promise<Department> {
    const department = await db('cf_department')
      .where('id', departmentId)
      .where('tenant_id', tenantId)
      .first();

    if (!department) {
      throw new Error('部门不存在');
    }

    if (updates.parent_id !== undefined && updates.parent_id !== department.parent_id) {
      await this.validateParentChange(departmentId, updates.parent_id, tenantId);
      
      if (updates.parent_id) {
        const newParent = await db('cf_department')
          .where('id', updates.parent_id)
          .where('tenant_id', tenantId)
          .first();
        
        updates.depth = newParent.depth + 1;
        updates.path = `${newParent.path}/${departmentId}`;
      } else {
        updates.depth = 1;
        updates.path = `/${departmentId}`;
      }

      await this.updateChildrenPaths(departmentId, updates.path as string, tenantId);
    }

    await db('cf_department')
      .where('id', departmentId)
      .update({
        ...updates,
        updated_at: new Date(),
      });

    await this.clearHierarchyCache(tenantId);

    await EventBusService.publish('hierarchy.department.updated', {
      departmentId,
      tenantId,
      updates,
      timestamp: new Date(),
    });

    logger.info(`[Hierarchy] Updated department ${departmentId}`);

    return await db('cf_department')
      .where('id', departmentId)
      .first();
  }

  /**
   * [BE-MT002-04] 删除部门
   */
  static async deleteDepartment(departmentId: string, tenantId: string): Promise<void> {
    const department = await db('cf_department')
      .where('id', departmentId)
      .where('tenant_id', tenantId)
      .first();

    if (!department) {
      throw new Error('部门不存在');
    }

    const childCount = await db('cf_department')
      .where('parent_id', departmentId)
      .count('id as count')
      .first();

    if (childCount && Number(childCount.count) > 0) {
      throw new Error('该部门下存在子部门，无法删除');
    }

    const shopCount = await db('cf_shop')
      .where('department_id', departmentId)
      .count('id as count')
      .first();

    if (shopCount && Number(shopCount.count) > 0) {
      throw new Error('该部门下存在店铺，无法删除');
    }

    await db('cf_department')
      .where('id', departmentId)
      .delete();

    await this.clearHierarchyCache(tenantId);

    await EventBusService.publish('hierarchy.department.deleted', {
      departmentId,
      tenantId,
      timestamp: new Date(),
    });

    logger.info(`[Hierarchy] Deleted department ${departmentId}`);
  }

  /**
   * [BE-MT002-05] 创建店铺
   */
  static async createShop(
    tenantId: string,
    departmentId: string,
    name: string,
    platform: string,
    shopCode: string
  ): Promise<Shop> {
    const department = await db('cf_department')
      .where('id', departmentId)
      .where('tenant_id', tenantId)
      .first();

    if (!department) {
      throw new Error('部门不存在');
    }

    const existingShop = await db('cf_shop')
      .where('tenant_id', tenantId)
      .where('shop_code', shopCode)
      .first();

    if (existingShop) {
      throw new Error('店铺编码已存在');
    }

    const id = `SHOP-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    const path = `${department.path}/${id}`;

    const shop: Partial<Shop> = {
      id,
      tenant_id: tenantId,
      department_id: departmentId,
      name,
      platform,
      shop_code: shopCode,
      path,
      depth: department.depth + 1,
      status: 'ACTIVE',
      created_at: new Date(),
      updated_at: new Date(),
    };

    await db('cf_shop').insert(shop);

    await this.clearHierarchyCache(tenantId);

    await EventBusService.publish('hierarchy.shop.created', {
      shopId: id,
      tenantId,
      departmentId,
      platform,
      timestamp: new Date(),
    });

    logger.info(`[Hierarchy] Created shop ${id} for tenant ${tenantId}`);

    return shop as Shop;
  }

  /**
   * [BE-MT002-06] 更新店铺
   */
  static async updateShop(
    shopId: string,
    tenantId: string,
    updates: Partial<Shop>
  ): Promise<Shop> {
    const shop = await db('cf_shop')
      .where('id', shopId)
      .where('tenant_id', tenantId)
      .first();

    if (!shop) {
      throw new Error('店铺不存在');
    }

    if (updates.department_id && updates.department_id !== shop.department_id) {
      const newDepartment = await db('cf_department')
        .where('id', updates.department_id)
        .where('tenant_id', tenantId)
        .first();

      if (!newDepartment) {
        throw new Error('目标部门不存在');
      }

      updates.path = `${newDepartment.path}/${shopId}`;
      updates.depth = newDepartment.depth + 1;
    }

    if (updates.shop_code && updates.shop_code !== shop.shop_code) {
      const existingShop = await db('cf_shop')
        .where('tenant_id', tenantId)
        .where('shop_code', updates.shop_code)
        .whereNot('id', shopId)
        .first();

      if (existingShop) {
        throw new Error('店铺编码已存在');
      }
    }

    await db('cf_shop')
      .where('id', shopId)
      .update({
        ...updates,
        updated_at: new Date(),
      });

    await this.clearHierarchyCache(tenantId);

    await EventBusService.publish('hierarchy.shop.updated', {
      shopId,
      tenantId,
      updates,
      timestamp: new Date(),
    });

    logger.info(`[Hierarchy] Updated shop ${shopId}`);

    return await db('cf_shop')
      .where('id', shopId)
      .first();
  }

  /**
   * [BE-MT002-07] 删除店铺
   */
  static async deleteShop(shopId: string, tenantId: string): Promise<void> {
    const shop = await db('cf_shop')
      .where('id', shopId)
      .where('tenant_id', tenantId)
      .first();

    if (!shop) {
      throw new Error('店铺不存在');
    }

    await db('cf_shop')
      .where('id', shopId)
      .delete();

    await this.clearHierarchyCache(tenantId);

    await EventBusService.publish('hierarchy.shop.deleted', {
      shopId,
      tenantId,
      timestamp: new Date(),
    });

    logger.info(`[Hierarchy] Deleted shop ${shopId}`);
  }

  /**
   * [BE-MT002-08] 获取层级统计
   */
  static async getHierarchyStats(tenantId: string): Promise<HierarchyStats> {
    const cacheKey = `${this.CACHE_PREFIX}stats:${tenantId}`;
    const cached = await RedisService.get(cacheKey);
    if (cached) {
      return JSON.parse(cached);
    }

    const [deptCount, shopStats, maxDepth] = await Promise.all([
      db('cf_department')
        .where('tenant_id', tenantId)
        .count('id as count')
        .first(),
      
      db('cf_shop')
        .where('tenant_id', tenantId)
        .select('status')
        .count('id as count')
        .groupBy('status'),
      
      db('cf_department')
        .where('tenant_id', tenantId)
        .max('depth as maxDepth')
        .first(),
    ]);

    const stats: HierarchyStats = {
      totalDepartments: Number(deptCount?.count || 0),
      totalShops: shopStats.reduce((sum, s) => sum + Number(s.count), 0),
      activeShops: Number(shopStats.find(s => s.status === 'ACTIVE')?.count || 0),
      inactiveShops: Number(shopStats.find(s => s.status === 'INACTIVE')?.count || 0),
      maxDepth: Number(maxDepth?.maxDepth || 0),
    };

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

    return stats;
  }

  /**
   * [BE-MT002-09] 获取部门树
   */
  static async getDepartmentTree(tenantId: string): Promise<HierarchyNode[]> {
    const cacheKey = `${this.CACHE_PREFIX}dept_tree:${tenantId}`;
    const cached = await RedisService.get(cacheKey);
    if (cached) {
      return JSON.parse(cached);
    }

    const departments = await db('cf_department')
      .where('tenant_id', tenantId)
      .where('status', 'ACTIVE')
      .orderBy('depth')
      .orderBy('name')
      .select('id', 'name', 'parent_id', 'path', 'depth');

    const nodeMap = new Map<string, HierarchyNode>();
    const rootNodes: HierarchyNode[] = [];

    departments.forEach(dept => {
      nodeMap.set(dept.id, {
        id: dept.id,
        type: 'DEPARTMENT',
        parentId: dept.parent_id,
        name: dept.name,
        path: dept.path,
        depth: dept.depth,
        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);
      }
    });

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

    return rootNodes;
  }

  /**
   * [BE-MT002-10] 获取部门下的店铺
   */
  static async getDepartmentShops(
    departmentId: string,
    tenantId: string,
    includeChildren: boolean = false
  ): Promise<Shop[]> {
    let query = db('cf_shop')
      .where('tenant_id', tenantId);

    if (includeChildren) {
      const department = await db('cf_department')
        .where('id', departmentId)
        .first('path');

      if (!department) {
        return [];
      }

      const childDeptIds = await db('cf_department')
        .where('tenant_id', tenantId)
        .where('path', 'like', `${department.path}%`)
        .pluck('id');

      query = query.whereIn('department_id', childDeptIds);
    } else {
      query = query.where('department_id', departmentId);
    }

    return query.orderBy('name');
  }

  /**
   * [BE-MT002-11] 获取用户层级上下文
   */
  static async getUserHierarchyContext(userId: string): Promise<{
    tenantId: string;
    departmentId?: string;
    shopId?: string;
    hierarchyPath: string;
  }> {
    const user = await db('cf_user')
      .where('id', userId)
      .first('tenant_id', 'department_id', 'shop_id', 'hierarchy_path');

    if (!user) {
      throw new Error('用户不存在');
    }

    return {
      tenantId: user.tenant_id,
      departmentId: user.department_id,
      shopId: user.shop_id,
      hierarchyPath: user.hierarchy_path || '',
    };
  }

  /**
   * [BE-MT002-12] 更新用户层级绑定
   */
  static async updateUserHierarchy(
    userId: string,
    tenantId: string,
    departmentId?: string,
    shopId?: string
  ): Promise<void> {
    let hierarchyPath = `/${tenantId}`;

    if (departmentId) {
      const department = await db('cf_department')
        .where('id', departmentId)
        .where('tenant_id', tenantId)
        .first('path');

      if (department) {
        hierarchyPath = department.path;
      }
    }

    if (shopId) {
      const shop = await db('cf_shop')
        .where('id', shopId)
        .where('tenant_id', tenantId)
        .first('path');

      if (shop) {
        hierarchyPath = shop.path;
      }
    }

    await db('cf_user')
      .where('id', userId)
      .update({
        tenant_id: tenantId,
        department_id: departmentId || null,
        shop_id: shopId || null,
        hierarchy_path: hierarchyPath,
        updated_at: new Date(),
      });

    await EventBusService.publish('hierarchy.user.updated', {
      userId,
      tenantId,
      departmentId,
      shopId,
      timestamp: new Date(),
    });

    logger.info(`[Hierarchy] Updated user ${userId} hierarchy binding`);
  }

  /**
   * 验证父节点变更
   */
  private static async validateParentChange(
    departmentId: string,
    newParentId: string | null,
    tenantId: string
  ): Promise<void> {
    if (!newParentId) return;

    if (departmentId === newParentId) {
      throw new Error('不能将部门设为自己的子部门');
    }

    const newParent = await db('cf_department')
      .where('id', newParentId)
      .where('tenant_id', tenantId)
      .first('path');

    if (!newParent) {
      throw new Error('父部门不存在');
    }

    if (newParent.path.includes(departmentId)) {
      throw new Error('不能将部门移动到自己的子部门下');
    }
  }

  /**
   * 更新子节点路径
   */
  private static async updateChildrenPaths(
    departmentId: string,
    newPath: string,
    tenantId: string
  ): Promise<void> {
    const children = await db('cf_department')
      .where('tenant_id', tenantId)
      .where('path', 'like', `%/${departmentId}/%`)
      .select('id', 'path');

    for (const child of children) {
      const updatedPath = child.path.replace(
        new RegExp(`.*${departmentId}`),
        newPath
      );
      
      await db('cf_department')
        .where('id', child.id)
        .update({ path: updatedPath });
    }

    const shops = await db('cf_shop')
      .where('tenant_id', tenantId)
      .where('path', 'like', `%/${departmentId}/%`)
      .select('id', 'path');

    for (const shop of shops) {
      const updatedPath = shop.path.replace(
        new RegExp(`.*${departmentId}`),
        newPath
      );
      
      await db('cf_shop')
        .where('id', shop.id)
        .update({ path: updatedPath });
    }
  }

  /**
   * 清除层级缓存
   */
  private static async clearHierarchyCache(tenantId: string): Promise<void> {
    await RedisService.deletePattern(`${this.CACHE_PREFIX}*:${tenantId}*`);
    logger.debug(`[Hierarchy] Cleared cache for tenant ${tenantId}`);
  }
}
