package com.srs.dormitory.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.srs.common.core.domain.AjaxResult;
import com.srs.common.core.domain.entity.SysDept;
import com.srs.common.core.domain.entity.SysUser;
import com.srs.common.core.page.TableDataInfo;
import com.srs.common.utils.SecurityUtils;
import com.srs.comprehensive.domain.CphTeacher;
import com.srs.comprehensive.mapper.CphTeacherMapper;
import com.srs.dormitory.domain.*;
import com.srs.dormitory.domain.Dto.DeptAllocationDto;
import com.srs.dormitory.domain.Dto.DmsSearch;
import com.srs.dormitory.domain.Dto.FastDto;
import com.srs.dormitory.domain.Dto.SelectDormDto;
import com.srs.dormitory.domain.Vo.DomInfo;
import com.srs.dormitory.domain.Vo.DormitoryVo;
import com.srs.dormitory.domain.Vo.ExportDmsReg;
import com.srs.dormitory.mapper.DmsDormitoryDeptMapper;
import com.srs.dormitory.mapper.DmsDormitoryFloorMapper;
import com.srs.dormitory.mapper.DmsDormitoryMapper;
import com.srs.dormitory.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.srs.dormitory.utils.PageUtil;
import com.srs.stureg.service.ISrsStuRegService;
import com.srs.system.mapper.SysDeptMapper;
import com.srs.system.service.ISysUserService;
import liquibase.pro.packaged.D;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static com.github.pagehelper.page.PageMethod.offsetPage;
import static com.srs.common.utils.PageUtils.startPage;

/**
 * <p>
 * 学院宿舍关联表 服务实现类
 * </p>
 *
 * @author 猪油骨
 * @since 2023-08-29
 */
@Service
//@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class IDmsDormitoryDeptServiceImpl extends ServiceImpl<DmsDormitoryDeptMapper, DmsDormitoryDept> implements IDmsDormitoryDeptService {
    @Autowired
    private IDmsDormitoryService dormitoryService;
    @Autowired
    private ISrsStuRegService regService;
    @Autowired
    private IDmsDormitoryClassService dormitoryClassService;
    @Autowired
    private IDmsDormitoryFloorService floorService;
    @Autowired
    private IDmsCampusService campusService;
    @Autowired
    private IDmsDormitoryParkService parkService;
    @Autowired
    private IDmsDormitoryBuildingService buildingService;
    @Autowired
    private ISysUserService userService;
    @Autowired
    private DmsDormitoryTeacherService teacherService;

    @Autowired
    private CphTeacherMapper teacherMapper;
    @Resource
    private SysDeptMapper sysDeptMapper;

    @Autowired
    public PlatformTransactionManager transactionManager;

    @Autowired
    public DmsDormitoryMapper _dmMapper;

    @Autowired
    public DmsDormitoryDeptMapper _dmDeptMapper;


    @Override
    public AjaxResult lockDept( DmsDormitoryDept param){
        try{
            QueryWrapper<DmsDormitoryDept> query = new QueryWrapper<>();
            query.eq("dormitory_id",param.getDormitoryId())
                    .eq("XYDM",param.getXydm())
                    .last("limit 1");
            DmsDormitoryDept tmp = _dmDeptMapper.selectOne(query);
            if(tmp == null){
                throw new Exception("没有该学院的分配记录，请重新分配");
            }
            tmp.isLock = "1";
            int res = _dmDeptMapper.updateById(tmp);
            if(res == 0){
                throw new Exception("删除失败");
            }

            return AjaxResult.success();
        }catch(Exception ex){
            return AjaxResult.error(ex.getMessage());
        }
    }

    @Override
    public AjaxResult lockAllDept(){
        try{
            QueryWrapper<DmsDormitoryDept> query = new QueryWrapper<>();
            query.ne("is_lock",1);
            List<DmsDormitoryDept> list = _dmDeptMapper.selectList(query);
            if(list.size() == 0){
                throw new Exception("暂无需要锁定的项目");
            }

            list.forEach(x->{
                x.isLock = "1";
            });
            boolean res = this.updateBatchById(list);
            if(!res){
                throw new Exception("锁定失败");
            }
            return AjaxResult.success();
        }catch(Exception ex){
            return AjaxResult.error(ex.getMessage());
        }
    }

    @Override
    public AjaxResult cancelDept( DmsDormitoryDept param){
        try{
            QueryWrapper<DmsDormitoryDept> query = new QueryWrapper<>();
            query.eq("dormitory_id",param.getDormitoryId())
                    .eq("XYDM",param.getXydm());
            int res = _dmDeptMapper.delete(query);
            if(res == 0){
                throw new Exception("删除失败");
            }

            return AjaxResult.success();
        }catch(Exception ex){
            return AjaxResult.error(ex.getMessage());
        }
    }

    @Override
    public List<ExportDmsReg> listSum(){
        return _dmDeptMapper.listSum();
    }


    @Override
    public AjaxResult deptBuildingCount(DmsSearch param){
        List<DomInfo> list = _dmDeptMapper.deptBuildingCount(param);
        return AjaxResult.success(list);
    }


    @Override
    public AjaxResult getDeptBedCount(){
        List<DomInfo> list = _dmDeptMapper.getDeptBedCount();
        return AjaxResult.success(list);
    }

    @Override
    public AjaxResult doFast(FastDto param){
        TransactionDefinition def = new DefaultTransactionDefinition();
        TransactionStatus status = transactionManager.getTransaction(def);
        try{

            List<DormitoryVo> dormList = new ArrayList<>();

            if(param.floorId == -1){
                Map<String,Object> searchQuery = new HashMap<>();
                searchQuery.put("buildingId",param.buildingId);
                List<DormitoryVo> tempDormList = _dmMapper.getCanDormList(searchQuery);

                List<Long> findIds = tempDormList.stream().map(DormitoryVo::getId).collect(Collectors.toList());
                QueryWrapper<DmsDormitoryDept> deptQuery = new QueryWrapper<>();
                deptQuery.in("dormitory_id",findIds)
                        .eq("is_lock",1);
                List<DmsDormitoryDept> deptList = _dmDeptMapper.selectList(deptQuery);
                if(deptList.size() != 0){
                    Set<Long> lockIds = deptList.stream().map(DmsDormitoryDept::getDormitoryId).collect(Collectors.toSet());
                    dormList = tempDormList.stream().filter(x->!lockIds.contains(x.getId())).collect(Collectors.toList());
                }else{
                    dormList = tempDormList;
                }

            }else if(param.dormitoryId.get(0) == -1){
                Map<String,Object> searchQuery = new HashMap<>();
                searchQuery.put("floorId",param.floorId);
                List<DormitoryVo> tempDormList = _dmMapper.getCanDormList(searchQuery);
                List<Long> findIds = tempDormList.stream().map(DormitoryVo::getId).collect(Collectors.toList());
                QueryWrapper<DmsDormitoryDept> deptQuery = new QueryWrapper<>();
                deptQuery.in("dormitory_id",findIds)
                        .eq("is_lock",1);
                List<DmsDormitoryDept> deptList = _dmDeptMapper.selectList(deptQuery);
                if(deptList.size() != 0){
                    Set<Long> lockIds = deptList.stream().map(DmsDormitoryDept::getDormitoryId).collect(Collectors.toSet());
                    dormList = tempDormList.stream().filter(x->!lockIds.contains(x.getId())).collect(Collectors.toList());
                }else{
                    dormList = tempDormList;
                }

            }else{
                MPJLambdaWrapper<DmsDormitory> searchQuery = new MPJLambdaWrapper<>();
                searchQuery.selectAs(DmsDormitory::getId, DormitoryVo::getId)
                        .selectAs(DmsDormitory::getOccupancy, DormitoryVo::getOccupancy)
                        .selectAs(DmsDormitory::getBedNum, DormitoryVo::getBedNum)
                        .in("id",param.dormitoryId)
                        .eq(DmsDormitory::getIsNew,"1");

                List<DormitoryVo> tempDormList = _dmMapper.selectJoinList(DormitoryVo.class,searchQuery);

                List<Long> findIds = tempDormList.stream().map(DormitoryVo::getId).collect(Collectors.toList());
                QueryWrapper<DmsDormitoryDept> deptQuery = new QueryWrapper<>();
                deptQuery.in("dormitory_id",findIds)
                        .eq("is_lock",1);
                List<DmsDormitoryDept> deptList = _dmDeptMapper.selectList(deptQuery);
                if(deptList.size() != 0){
                    Set<Long> lockIds = deptList.stream().map(DmsDormitoryDept::getDormitoryId).collect(Collectors.toSet());
                    dormList = tempDormList.stream().filter(x->!lockIds.contains(x.getId())).collect(Collectors.toList());
                }else{
                    dormList = tempDormList;
                }
            }


            List<Long> dormId = new ArrayList<>();
            List<DmsDormitoryDept> needInsertList = new ArrayList<>();

            for(DormitoryVo item:dormList){
                dormId.add(item.getId());

                DmsDormitoryDept temp = new DmsDormitoryDept();
                temp.setDormitoryId(item.getId());
                temp.setXydm(param.deptCode);
                temp.setGradeCode(param.gradeCode);
                temp.setBedCount( item.getBedNum() - item.getOccupancy() );
                needInsertList.add(temp);
            }

            if(dormId.size() == 0){
                throw new Exception("出现错误，该楼栋无房间可分配或之前的分配已锁定");
            }
            QueryWrapper<DmsDormitoryDept> dormDeptQuery = new QueryWrapper<>();
            dormDeptQuery.in("dormitory_id",dormId);
            _dmDeptMapper.delete(dormDeptQuery);

            boolean res = this.saveBatch(needInsertList);
            if(!res){
                throw new Exception("插入失败");
            }

            transactionManager.commit(status);
            return AjaxResult.success();
        }catch(Exception ex){
            transactionManager.rollback(status);
            return AjaxResult.error(ex.getMessage());
        }
    }

    @Override
    public AjaxResult changeDeptBed(List<DmsDormitoryDept> param){
        TransactionDefinition def = new DefaultTransactionDefinition();
        TransactionStatus status = transactionManager.getTransaction(def);
        try{
            Long dmId = param.get(0).getDormitoryId();
//            DmsDormitory dm = _dmMapper.selectById(dmId);
            DmsDormitory dm = _dmMapper.getDormitoryById(dmId);

            if(dm == null){
                throw new Exception("该宿舍不存在，请重新输入");
            }
            int canBed = dm.getBedNum() - dm.getOccupancy();
            AtomicInteger totalTemp = new AtomicInteger();
            param.forEach(x->{
                totalTemp.addAndGet(x.bedCount);
            });

            if(totalTemp.intValue() > canBed){
                throw new Exception("分配的床位数量大于可用床位数量");
            }

            param.forEach(x->{
                QueryWrapper<DmsDormitoryDept> dmDeptQuery = new QueryWrapper<>();
                dmDeptQuery.eq("XYDM",x.getXydm());
                dmDeptQuery.eq("dormitory_id",x.getDormitoryId());
                DmsDormitoryDept temp = _dmDeptMapper.selectOne(dmDeptQuery);
                if(temp != null){
                    x.setId(temp.getId());
                }
            });

            boolean res = this.saveOrUpdateBatch(param);
            if(!res){
                throw new Exception("保存失败");
            }

            transactionManager.commit(status);
            return AjaxResult.success();
        }catch(Exception ex){
            transactionManager.rollback(status);
            return AjaxResult.error(ex.getMessage());
        }
    }


    /**
     * 分配学院宿舍
     *
     * @param dto 学院宿舍分配DTO
     * @return 操作结果
     */
    @Override
    public AjaxResult allocation(DeptAllocationDto dto) {
        TransactionDefinition def = new DefaultTransactionDefinition();
        TransactionStatus status = transactionManager.getTransaction(def);
        try{

//            QueryWrapper<DmsDormitory> dmQuery = new QueryWrapper<>();
//            dmQuery.in("id",dto.getDormIds());
            List<DmsDormitory> dmList = _dmMapper.listViewDormInfoByIds(dto.getDormIds());

            List<String> isExistXydm = new ArrayList<>();

            QueryWrapper<DmsDormitoryDept> dmDeptQuery = new QueryWrapper<>();
            dmDeptQuery.in("dormitory_id",dto.getDormIds());

            List<DmsDormitoryDept> isExistDmDept = _dmDeptMapper.selectList(dmDeptQuery);

            isExistDmDept.forEach(x->{
                isExistXydm.add(x.getXydm());
            });

            isExistXydm.addAll(dto.getXydm());

            Set<String> xydms = new HashSet<>(isExistXydm);

            int xyCount = xydms.size();
            List<DmsDormitoryDept> tempDmDept = new ArrayList<>(); //暂存的宿舍学院
            for(Long dmId : dto.getDormIds()){
                DmsDormitory dmBed = dmList.stream().filter(x-> Objects.equals(x.getId(), dmId)).findFirst().orElse(null);
                if (dmBed != null) {
                    int bedNum = dmBed.getBedNum() - dmBed.getOccupancy();
                    int avgBedNum = bedNum / xyCount;
                    int i = 1;
                    for(String xydm:xydms){
                        DmsDormitoryDept temp = new DmsDormitoryDept();
                        temp.setDormitoryId(dmId);
                        temp.setXydm(xydm);
                        temp.setGradeCode(String.valueOf(LocalDate.now().getYear()));
                        if(i == xyCount){
                            int bedCount = bedNum - (avgBedNum * (xyCount -1 ));
                            temp.setBedCount(bedCount);
                        }else{
                            temp.setBedCount(avgBedNum);
                            i++;
                        }
                        tempDmDept.add(temp);
                    }
                }
            }

            if(isExistDmDept.size() != 0){
                for(DmsDormitoryDept dmDept : isExistDmDept){
                    tempDmDept.forEach(x->{
                        if(Objects.equals(x.getXydm(), dmDept.getXydm()) && Objects.equals(x.getDormitoryId(), dmDept.getDormitoryId())){
                            x.setId(dmDept.getId());
                        }
                    });
                }
            }

            // 批量保存分配记录
            boolean saveBatch = this.saveOrUpdateBatch(tempDmDept);
            if (!saveBatch) {
                throw new RuntimeException("操作失败");
            }
            transactionManager.commit(status);
            return AjaxResult.success();
        }catch(Exception ex){
            transactionManager.rollback(status);
            return AjaxResult.error(ex.getMessage());
        }
    }

    @Override
    @Transactional
    public int unbind(List<Long> dormitoryIds, List<String> academyCode) {
        LambdaQueryWrapper<DmsDormitoryDept> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(DmsDormitoryDept::getDormitoryId, dormitoryIds)
                .in(DmsDormitoryDept::getXydm, academyCode);
        boolean remove = remove(wrapper);
        if (!remove) throw new RuntimeException("取消失败");
        return 1;
    }

    /**
     * 获取宿舍信息列表
     *
     * @param dto 宿舍查询DTO
     * @return 宿舍信息列表，包含宿舍的相关属性和所选学院信息
     */
    @Override
    public TableDataInfo getDormitory(SelectDormDto dto) {

        DmsSearch param = new DmsSearch();

        if (dto.getFloorId() != null) {
            param.floorId = dto.getFloorId();
        }
        param.buildingId = dto.getBuildingId();
        param.isNew = "1";
        // 分页查询宿舍信息
        startPage();
        List<DomInfo> list = _dmMapper.listDormInfo(param);

        if (list.isEmpty()) return PageUtil.getDataTable(new ArrayList<>(), null);

        List<Long> ids = list
                .stream()
                .map(DomInfo::getId)
                .collect(Collectors.toList());

        // 查询宿舍和学院关联信息
        List<DmsDormitoryDept> dormitoryDepts = lambdaQuery()
                .in(DmsDormitoryDept::getDormitoryId, ids)
                .list();

        List<String> xydm = dormitoryDepts
                .stream()
                .map(DmsDormitoryDept::getXydm)
                .collect(Collectors.toList());

        List<Map<String, Object>> maps;
        if (!xydm.isEmpty()) {
            maps = baseMapper.selectRegByXydm(xydm);
        } else {
            maps = new ArrayList<>();
        }

        List<Map<String, Object>> listOfDormitories = list.stream()
                .map(dormitory -> {
                    Map<String, Object> map = new HashMap<>();
                    List<Map<String, Object>> mapList = new ArrayList<>();
                    if (!maps.isEmpty()) {
                        mapList = maps
                                .stream()
                                .filter(map1 -> map1.get("dormitory_id")
                                        .toString()
                                        .equals(dormitory.getId().toString()))
                                .collect(Collectors.toList());
                    }

                    map.put("id", dormitory.getId());
                    map.put("roomNo", dormitory.getRoomNo());
                    map.put("occupancy", dormitory.getOccupancy());
                    map.put("bedNum", dormitory.getBedNum() - dormitory.getOccupancy());
                    map.put("gender",dormitory.gender);
                    map.put("selected", mapList);
                    return map;
                }).collect(Collectors.toList());


        return PageUtil.getDataTable(listOfDormitories, list);
        // 构建返回的宿舍信息列表
    }

    /**
     * 获取学院信息列表
     *
     * @return 学院信息列表，每个元素是一个包含学院代码（XYDM）和学院名称（XY）的 Map 对象
     */
    @Override
    public AjaxResult getDept() {
        List<SysDept> sysDeptList = new LambdaQueryChainWrapper<>(sysDeptMapper)
                .like(SysDept::getDeptCode, "1160804")
                .notIn(SysDept::getDeptCode, new Object[]{"1160804"})
                .list();
        // 将学院信息转换为 Map 对象列表
        return AjaxResult.success(sysDeptList);

    }

    /**
     * 获取宿舍楼信息列表
     *
     * @param parkId 查询条件，包括楼栋ID等信息
     * @return 包含宿舍楼相关信息的列表，每个元素是一个包含楼栋ID、楼栋名称等信息的 Map 对象
     */
    @Override
    public TableDataInfo getBuilding(Long parkId) {
        // 查询宿舍楼信息
        List<DmsDormitoryBuilding> list = buildingService
                .lambdaQuery()
                .eq(DmsDormitoryBuilding::getParkId, parkId)
                .inSql(DmsDormitoryBuilding::getId, "SELECT \n" +
                        "    id\n" +
                        "FROM \n" +
                        "    dms_dormitory_building\n" +
                        "WHERE \n" +
                        "    id IN (\n" +
                        "        SELECT \n" +
                        "            building_id \n" +
                        "        FROM \n" +
                        "            dms_dormitory_floor \n" +
                        "        WHERE \n" +
                        "            id IN (\n" +
                        "                SELECT \n" +
                        "                    floor_id \n" +
                        "                FROM \n" +
                        "                    dms_dormitory \n" +
                        "                WHERE \n" +
                        "                    bed_num NOT IN (0) \n" +
                        "                    AND \n" +
                        "                    `is_new` IN (1)\n" +
                        "                    AND \n" +
                        "                    bed_num - occupancy > 0\n" +
                        "            )\n" +
                        "    )\n")
                .list();
        return PageUtil.getDataTable(list, null);

    }

    /**
     * 根据楼栋ID查询楼层信息
     *
     * @param buildingId 楼栋ID
     * @return 楼层信息列表，每个元素是一个包含楼层ID（id）和楼层名称（floor）的 Map 对象
     */
    @Override
    public TableDataInfo getFloor(Long buildingId) {
        // 查询指定楼栋的楼层信息
        List<DmsDormitoryFloor> list = floorService
                .lambdaQuery()
                .eq(DmsDormitoryFloor::getBuildingId, buildingId)
                .inSql(DmsDormitoryFloor::getId, "SELECT id \n" +
                        "FROM dms_dormitory_floor \n" +
                        "WHERE id IN (\n" +
                        "    SELECT floor_id \n" +
                        "    FROM dms_dormitory \n" +
                        "    WHERE \n" +
                        "        bed_num NOT IN (0) \n" +
                        "        AND `is_new` IN (1) \n" +
                        "        AND bed_num - occupancy > 0\n" +
                        ")\n" +
                        "AND building_id = " + buildingId)
                .list();
        // 将楼层信息转换为 Map 对象列表
        return PageUtil.getDataTable(
                list.stream().map(l -> {
                    Map<String, Object> map = new HashMap<>();
                    map.put("id", l.getId());
                    map.put("floor", l.getFloor());
                    return map;
                }).collect(Collectors.toList()), list);

    }

    @Override
    public TableDataInfo getPark(Long campusId) {
        return PageUtil.getDataTable(
                parkService
                        .lambdaQuery()
                        .eq(DmsDormitoryPark::getCampusId, campusId)
                        .list()
                        .stream()
                        .map(dmsDormitoryPark -> {
                            HashMap<String, Object> map = new HashMap<>();
                            map.put("id", dmsDormitoryPark.getId());
                            map.put("parkName", dmsDormitoryPark.getName());
                            return map;
                        })
                        .collect(Collectors.toList()), null);
    }

    @Override
    public AjaxResult getCampus() {
        return AjaxResult.success(campusService.list());
    }

    @Override
    public TableDataInfo viewTeacher() {
        String username = SecurityUtils.getUsername();
        SysUser user = userService.selectUserByUserName(username);
        SysDept dept = user.getDept();
        startPage();
        List<CphTeacher> teachers = teacherMapper.selectList(new LambdaQueryWrapper<>(CphTeacher.class)
                .select(CphTeacher::getTeacherId, CphTeacher::getEmployeeId, CphTeacher::getName)
                .eq(CphTeacher::getDeptId, dept.getDeptId()));
        System.out.println(teachers);
        return PageUtil.getDataTable(teachers);
    }

    @Override
    public AjaxResult assignTeachers(Long dormId, Long employeeId) {
        DmsDormitoryTeacher dormitoryTeacher = new DmsDormitoryTeacher();
        dormitoryTeacher.setDormitoryId(Math.toIntExact(dormId));
        dormitoryTeacher.setEmployeeId(employeeId.intValue());
        boolean save = teacherService.save(dormitoryTeacher);
        if (!save) throw new RuntimeException("保存失败");
        return AjaxResult.success();
    }

    @Override
    public TableDataInfo viewDormitory() {
        String username = SecurityUtils.getUsername();
        SysUser user = userService.selectUserByUserName(username);
        SysDept dept = user.getDept();
        startPage();
        List<DmsDormitoryDept> list = this.lambdaQuery().eq(DmsDormitoryDept::getXydm, dept.getDeptCode()).list();
        return PageUtil.getDataTable(list);
    }
}


