import { Injectable, NotFoundException, BadRequestException, ConflictException } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import {
  AddUserDepartmentDto,
  UpdateUserDepartmentDto,
  UserDepartmentQueryDto,
} from './dto';
import {
  IamUserNotInDepartmentException,
  IamUserAlreadyInDepartmentException,
  IamCannotRemovePrimaryDepartmentException,
  IamManagerNotInDepartmentException,
  IamManagerSelfReferenceException,
  IamManagerLoopException,
} from '../exceptions';

@Injectable()
export class UserDepartmentsService {
  constructor(private prisma: PrismaService) {}

  /**
   * 获取用户的所有部门归属
   */
  async getUserDepartments(userId: string) {
    const user = await this.prisma.user.findUnique({
      where: { id: userId, deletedAt: null },
    });

    if (!user) {
      throw new NotFoundException('User not found');
    }

    const memberships = await this.prisma.userDepartment.findMany({
      where: { 
        userId,
        leftAt: null, // ✅ 修复：只查询仍在职的部门归属
      },
      include: {
        department: {
          select: {
            id: true,
            name: true,
            code: true,
          },
        },
        position: {
          select: {
            id: true,
            name: true,
            level: true,
          },
        },
        manager: {
          select: {
            id: true,
            displayName: true,
            email: true,
          },
        },
      },
      orderBy: [
        { isPrimary: 'desc' },
        { createdAt: 'asc' },
      ],
    });

    // ✅ 修复：直接返回数组，符合API文档定义
    // API 响应会自动包装成 { success: true, data: [...], timestamp: "..." }
    return memberships;
  }

  /**
   * 添加用户部门归属
   */
  async addUserDepartment(userId: string, dto: AddUserDepartmentDto) {
    const user = await this.prisma.user.findUnique({
      where: { id: userId, deletedAt: null },
    });

    if (!user) {
      throw new NotFoundException('User not found');
    }

    // 检查用户是否已属于该部门
    const existing = await this.prisma.userDepartment.findUnique({
      where: {
        userId_departmentId: {
          userId,
          departmentId: dto.departmentId,
        },
      },
    });

    if (existing) {
      throw new IamUserAlreadyInDepartmentException();
    }

    // 验证部门存在
    const department = await this.prisma.department.findUnique({
      where: { id: dto.departmentId, deletedAt: null },
    });

    if (!department) {
      throw new NotFoundException('Department not found');
    }

    // 验证岗位存在
    if (dto.positionId) {
      const position = await this.prisma.position.findUnique({
        where: { id: dto.positionId, deletedAt: null },
      });

      if (!position) {
        throw new NotFoundException('Position not found');
      }
    }

    // 验证上级存在且为同部门成员（包括环路检测）
    if (dto.managerId) {
      await this.validateManager(dto.departmentId, dto.managerId, userId);
    }

    // 如果设为主部门，需要先取消其他主部门
    if (dto.isPrimary) {
      await this.prisma.userDepartment.updateMany({
        where: { userId, isPrimary: true },
        data: { isPrimary: false },
      });
    }

    // 如果用户还没有任何部门归属，自动设为主部门
    const userDeptCount = await this.prisma.userDepartment.count({
      where: { userId },
    });

    const isPrimary = dto.isPrimary !== undefined ? dto.isPrimary : userDeptCount === 0;

    // v2.1: 获取 department 的 organizationId
    const deptInfo = await this.prisma.department.findUnique({
      where: { id: dto.departmentId },
      select: { organizationId: true },
    });

    if (!deptInfo) {
      throw new Error(`Department ${dto.departmentId} not found`);
    }

    const membership = await this.prisma.userDepartment.create({
      data: {
        userId,
        departmentId: dto.departmentId,
        organizationId: deptInfo.organizationId, // v2.1: 必填字段
        positionId: dto.positionId,
        managerId: dto.managerId,
        isPrimary,
        title: dto.title,
        joinedAt: dto.joinedAt ? new Date(dto.joinedAt) : new Date(),
      },
      include: {
        department: {
          select: {
            id: true,
            name: true,
            code: true,
          },
        },
        position: {
          select: {
            id: true,
            name: true,
            level: true,
          },
        },
        manager: {
          select: {
            id: true,
            displayName: true,
            email: true,
          },
        },
      },
    });

    return membership;
  }

  /**
   * 更新用户部门归属
   */
  async updateUserDepartment(
    userId: string,
    departmentId: string,
    dto: UpdateUserDepartmentDto,
  ) {
    const membership = await this.prisma.userDepartment.findUnique({
      where: {
        userId_departmentId: {
          userId,
          departmentId,
        },
      },
    });

    if (!membership) {
      throw new IamUserNotInDepartmentException();
    }

    // 验证岗位存在
    if (dto.positionId) {
      const position = await this.prisma.position.findUnique({
        where: { id: dto.positionId, deletedAt: null },
      });

      if (!position) {
        throw new NotFoundException('Position not found');
      }
    }

    // 验证上级存在且为同部门成员（包括环路检测）
    if (dto.managerId) {
      await this.validateManager(departmentId, dto.managerId, userId);
    }

    const updated = await this.prisma.userDepartment.update({
      where: {
        userId_departmentId: {
          userId,
          departmentId,
        },
      },
      data: {
        ...dto,
        leftAt: dto.leftAt ? new Date(dto.leftAt) : undefined,
      },
      include: {
        department: {
          select: {
            id: true,
            name: true,
            code: true,
          },
        },
        position: {
          select: {
            id: true,
            name: true,
            level: true,
          },
        },
        manager: {
          select: {
            id: true,
            displayName: true,
            email: true,
          },
        },
      },
    });

    return updated;
  }

  /**
   * 设置主部门
   */
  async setPrimaryDepartment(userId: string, departmentId: string) {
    const membership = await this.prisma.userDepartment.findUnique({
      where: {
        userId_departmentId: {
          userId,
          departmentId,
        },
      },
    });

    if (!membership) {
      throw new IamUserNotInDepartmentException();
    }

    // 使用事务确保原子性
    await this.prisma.$transaction([
      // 取消其他主部门
      this.prisma.userDepartment.updateMany({
        where: { userId, isPrimary: true },
        data: { isPrimary: false },
      }),
      // 设置新的主部门
      this.prisma.userDepartment.update({
        where: {
          userId_departmentId: {
            userId,
            departmentId,
          },
        },
        data: { isPrimary: true },
      }),
    ]);

    return { 
      userId, 
      departmentId,
      message: 'Primary department updated successfully' 
    };
  }

  /**
   * 移除用户部门归属
   */
  async removeUserDepartment(userId: string, departmentId: string) {
    const membership = await this.prisma.userDepartment.findUnique({
      where: {
        userId_departmentId: {
          userId,
          departmentId,
        },
      },
    });

    if (!membership) {
      throw new IamUserNotInDepartmentException();
    }

    // 如果删除的是主部门，自动将另一个部门设为主部门
    let warning: string | undefined;
    if (membership.isPrimary) {
      // 查找用户的其他部门
      const otherDepartments = await this.prisma.userDepartment.findMany({
        where: {
          userId,
          departmentId: { not: departmentId },
        },
        orderBy: { joinedAt: 'asc' },
        take: 1,
      });

      if (otherDepartments.length > 0) {
        // 自动将最早加入的部门设为主部门
        await this.prisma.userDepartment.update({
          where: {
            userId_departmentId: {
              userId,
              departmentId: otherDepartments[0].departmentId,
            },
          },
          data: { isPrimary: true },
        });
        warning = `Primary department removed. Another department has been automatically set as primary.`;
      } else {
        // 这是用户的最后一个部门
        warning = `Primary department removed. User has no departments now.`;
      }
    }

    await this.prisma.userDepartment.delete({
      where: {
        userId_departmentId: {
          userId,
          departmentId,
        },
      },
    });

    return { 
      message: 'Department membership removed successfully',
      warning,
    };
  }

  /**
   * 验证上级是否为同部门成员
   */
  private async validateManager(departmentId: string, managerId: string, userId?: string) {
    const manager = await this.prisma.user.findUnique({
      where: { id: managerId, deletedAt: null },
    });

    if (!manager) {
      throw new NotFoundException('Manager not found');
    }

    // 1. 检查自引用：不能将自己设为自己的上级
    if (userId && managerId === userId) {
      throw new IamManagerSelfReferenceException();
    }

    // 2. 检查上级是否为该部门成员（且仍在职）
    const managerMembership = await this.prisma.userDepartment.findUnique({
      where: {
        userId_departmentId: {
          userId: managerId,
          departmentId,
        },
      },
    });

    if (!managerMembership || managerMembership.leftAt) {
      throw new IamManagerNotInDepartmentException();
    }

    // 3. 环路检测：在同一部门内，从 managerId 向上遍历，看是否会遇到 userId
    if (userId) {
      await this.detectManagerLoop(departmentId, managerId, userId);
    }
  }

  /**
   * 检测汇报关系环路
   * 从 managerId 开始向上追溯，如果遇到 userId 则说明形成环路
   */
  private async detectManagerLoop(departmentId: string, managerId: string, userId: string) {
    const maxDepth = 20; // 防止无限循环
    let currentId = managerId;
    let depth = 0;

    while (currentId && depth < maxDepth) {
      // 查找当前用户在该部门的上级（只查在职成员）
      const membership = await this.prisma.userDepartment.findUnique({
        where: {
          userId_departmentId: {
            userId: currentId,
            departmentId,
          },
        },
        select: {
          managerId: true,
          leftAt: true,
        },
      });

      // 如果没有上级或已离职，则到达顶端，无环路
      if (!membership || membership.leftAt || !membership.managerId) {
        break;
      }

      // 如果上级是 userId，则形成环路
      if (membership.managerId === userId) {
        throw new IamManagerLoopException();
      }

      currentId = membership.managerId;
      depth++;
    }

    // 如果达到最大深度，说明可能有问题，但不一定是环路
    // 这里选择不抛出异常，让其通过（也可以选择抛出异常）
    if (depth >= maxDepth) {
      console.warn(`Manager chain depth exceeded ${maxDepth} levels for department ${departmentId}`);
    }
  }

  /**
   * 获取用户的主部门信息
   */
  async getUserPrimaryDepartment(userId: string) {
    const primary = await this.prisma.userDepartment.findFirst({
      where: {
        userId,
        isPrimary: true,
      },
      include: {
        department: true,
        position: true,
        manager: {
          select: {
            id: true,
            displayName: true,
            email: true,
          },
        },
      },
    });

    return primary;
  }
}

