import { Injectable, NotFoundException, ConflictException, BadRequestException } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import { CreateDepartmentDto } from './dto/create-department.dto';
import { UpdateDepartmentDto } from './dto/update-department.dto';

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

  async create(createDepartmentDto: CreateDepartmentDto, tenantId: number, creatorId?: number) {
    // 检查部门编码是否已存在
    const existingByCode = await this.prisma.department.findFirst({
      where: {
        tenantId,
        code: createDepartmentDto.code,
      },
    });

    if (existingByCode) {
      throw new ConflictException('部门编码已存在');
    }

    // 如果指定了父部门，验证父部门是否存在且属于该租户
    if (createDepartmentDto.parentId) {
      const parent = await this.prisma.department.findFirst({
        where: {
          id: createDepartmentDto.parentId,
          tenantId,
          validState: 1,
        },
      });

      if (!parent) {
        throw new NotFoundException('父部门不存在或不属于该租户');
      }
    }

    const data: any = {
      ...createDepartmentDto,
      tenantId,
    };

    if (creatorId) {
      data.creator = creatorId;
    }

    return this.prisma.department.create({
      data,
      include: {
        parent: true,
        _count: {
          select: {
            teachers: {
              where: {
                validState: 1,
              },
            },
            children: {
              where: {
                validState: 1,
              },
            },
          },
        },
      },
    });
  }

  async findAll(page: number = 1, pageSize: number = 10, tenantId?: number, parentId?: number) {
    const skip = (page - 1) * pageSize;
    const where: any = { validState: 1 };
    
    if (tenantId) {
      where.tenantId = tenantId;
    }
    
    if (parentId !== undefined) {
      where.parentId = parentId;
    }

    const [list, total] = await Promise.all([
      this.prisma.department.findMany({
        where,
        skip,
        take: pageSize,
        orderBy: [
          { sort: 'desc' },
          { name: 'asc' },
        ],
        include: {
          parent: true,
          _count: {
            select: {
              teachers: {
                where: {
                  validState: 1,
                },
              },
              children: {
                where: {
                  validState: 1,
                },
              },
            },
          },
        },
      }),
      this.prisma.department.count({ where }),
    ]);

    return {
      list,
      total,
      page,
      pageSize,
    };
  }

  async findTree(tenantId?: number) {
    const where: any = { validState: 1 };
    if (tenantId) {
      where.tenantId = tenantId;
    }

    const departments = await this.prisma.department.findMany({
      where,
      orderBy: [
        { sort: 'desc' },
        { name: 'asc' },
      ],
      include: {
        _count: {
          select: {
            teachers: {
              where: {
                validState: 1,
              },
            },
            children: {
              where: {
                validState: 1,
              },
            },
          },
        },
      },
    });

    // 构建树形结构
    const buildTree = (items: any[], parentId: number | null = null): any[] => {
      return items
        .filter(item => item.parentId === parentId)
        .map(item => ({
          ...item,
          children: buildTree(items, item.id),
        }));
    };

    return buildTree(departments);
  }

  async findOne(id: number, tenantId?: number) {
    const where: any = { id, validState: 1 };
    if (tenantId) {
      where.tenantId = tenantId;
    }

    const department = await this.prisma.department.findFirst({
      where,
      include: {
        parent: true,
        children: {
          where: {
            validState: 1,
          },
        },
        teachers: {
          where: {
            validState: 1,
          },
          include: {
            user: true,
          },
        },
      },
    });

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

    return department;
  }

  async update(id: number, updateDepartmentDto: UpdateDepartmentDto, tenantId?: number, modifierId?: number) {
    // 验证部门是否存在
    const existingDepartment = await this.findOne(id, tenantId);

    const data: any = {};

    // 如果更新编码，检查是否冲突
    if (updateDepartmentDto.code && updateDepartmentDto.code !== existingDepartment.code) {
      const existingByCode = await this.prisma.department.findFirst({
        where: {
          tenantId: tenantId || existingDepartment.tenantId,
          code: updateDepartmentDto.code,
          id: { not: id },
        },
      });

      if (existingByCode) {
        throw new ConflictException('部门编码已存在');
      }
      data.code = updateDepartmentDto.code;
    }

    // 如果更新父部门，验证父部门是否存在且不会造成循环引用
    if (updateDepartmentDto.parentId !== undefined) {
      if (updateDepartmentDto.parentId === id) {
        throw new BadRequestException('不能将部门设置为自己的父部门');
      }

      if (updateDepartmentDto.parentId !== null) {
        const parent = await this.prisma.department.findFirst({
          where: {
            id: updateDepartmentDto.parentId,
            tenantId: tenantId || existingDepartment.tenantId,
            validState: 1,
          },
        });

        if (!parent) {
          throw new NotFoundException('父部门不存在或不属于该租户');
        }

        // 检查是否会造成循环引用（父部门不能是当前部门的子部门）
        const isDescendant = await this.checkIsDescendant(
          updateDepartmentDto.parentId,
          id,
          tenantId || existingDepartment.tenantId,
        );

        if (isDescendant) {
          throw new BadRequestException('不能将部门设置为其子部门的父部门');
        }
      }
      data.parentId = updateDepartmentDto.parentId;
    }

    if (updateDepartmentDto.name) {
      data.name = updateDepartmentDto.name;
    }

    if (updateDepartmentDto.description !== undefined) {
      data.description = updateDepartmentDto.description;
    }

    if (updateDepartmentDto.sort !== undefined) {
      data.sort = updateDepartmentDto.sort;
    }

    if (modifierId) {
      data.modifier = modifierId;
    }

    return this.prisma.department.update({
      where: { id },
      data,
      include: {
        parent: true,
        _count: {
          select: {
            teachers: {
              where: {
                validState: 1,
              },
            },
            children: {
              where: {
                validState: 1,
              },
            },
          },
        },
      },
    });
  }

  async remove(id: number, tenantId?: number) {
    // 验证部门是否存在
    const department = await this.findOne(id, tenantId);

    // 检查是否有子部门
    const childrenCount = await this.prisma.department.count({
      where: {
        parentId: id,
        validState: 1,
      },
    });

    if (childrenCount > 0) {
      throw new BadRequestException('删除部门前需先删除或转移所有子部门');
    }

    // 检查是否有教师
    const teacherCount = await this.prisma.teacher.count({
      where: {
        departmentId: id,
        validState: 1,
      },
    });

    if (teacherCount > 0) {
      throw new BadRequestException('删除部门前需先转移或删除该部门下的所有教师');
    }

    // 软删除
    return this.prisma.department.update({
      where: { id },
      data: {
        validState: 2,
      },
    });
  }

  private async checkIsDescendant(parentId: number, childId: number, tenantId: number): Promise<boolean> {
    const parent = await this.prisma.department.findFirst({
      where: {
        id: parentId,
        tenantId,
        validState: 1,
      },
      include: {
        children: {
          where: {
            validState: 1,
          },
        },
      },
    });

    if (!parent) {
      return false;
    }

    // 检查直接子部门
    if (parent.children.some(child => child.id === childId)) {
      return true;
    }

    // 递归检查所有子部门
    for (const child of parent.children) {
      if (await this.checkIsDescendant(child.id, childId, tenantId)) {
        return true;
      }
    }

    return false;
  }
}

