package com.xjrsoft.module.room.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.xjrsoft.common.page.ConventPage;
import com.xjrsoft.common.utils.VoToColumnUtil;
import com.xjrsoft.module.base.entity.BaseClass;
import com.xjrsoft.module.base.entity.BaseOfficeBuild;
import com.xjrsoft.module.base.mapper.BaseClassMapper;
import com.xjrsoft.module.room.dto.RoomBedCheckRecordPageDto;
import com.xjrsoft.module.room.entity.*;
import com.xjrsoft.module.room.mapper.RoomBedCheckRecordMapper;
import com.xjrsoft.module.room.mapper.RoomBedCheckRecordRelationMapper;
import com.xjrsoft.module.room.mapper.RoomMapper;
import com.xjrsoft.module.room.service.IRoomBedCheckRecordService;
import com.xjrsoft.module.room.vo.*;
import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
import com.xjrsoft.module.system.entity.DictionaryDetail;
import com.xjrsoft.module.system.entity.File;
import com.xjrsoft.module.system.service.IFileService;
import com.xjrsoft.module.teacher.entity.XjrUser;
import com.xjrsoft.module.teacher.mapper.XjrUserMapper;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
* @title: 查寝记录
* @Author szs
* @Date: 2024-01-02
* @Version 1.0
*/
@Service
@AllArgsConstructor
public class RoomBedCheckRecordServiceImpl extends MPJBaseServiceImpl<RoomBedCheckRecordMapper, RoomBedCheckRecord> implements IRoomBedCheckRecordService {
    private final RoomBedCheckRecordMapper roomBedCheckRecordRoomBedCheckRecordMapper;

    private final RoomBedCheckRecordRelationMapper roomBedCheckRecordRoomBedCheckRecordRelationMapper;

    private final IFileService fileService;

    private final RoomMapper roomMapper;

    private final XjrUserMapper xjrUserMapper;

    private final BaseClassMapper baseClassMapper;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(RoomBedCheckRecord roomBedCheckRecord) {
        roomBedCheckRecord.setUserId(StpUtil.getLoginIdAsLong());
        roomBedCheckRecordRoomBedCheckRecordMapper.insert(roomBedCheckRecord);
        for (RoomBedCheckRecordRelation roomBedCheckRecordRelation : roomBedCheckRecord.getRoomBedCheckRecordRelationList()) {
            roomBedCheckRecordRelation.setRoomBedCheckRecordId(roomBedCheckRecord.getId());
            Room room = roomMapper.selectById(roomBedCheckRecordRelation.getRoomId());
            roomBedCheckRecordRelation.setRoomName(room.getRoomName());
            roomBedCheckRecordRelation.setFloorNumber(room.getFloorNumber());
            roomBedCheckRecordRelation.setOfficeBuildId(room.getOfficeBuildId());
            roomBedCheckRecordRoomBedCheckRecordRelationMapper.insert(roomBedCheckRecordRelation);
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(RoomBedCheckRecord roomBedCheckRecord) {
        roomBedCheckRecordRoomBedCheckRecordMapper.updateById(roomBedCheckRecord);
        //********************************* RoomBedCheckRecordRelation  增删改  开始 *******************************************/
        {
            // 查出所有子级的id
            List<RoomBedCheckRecordRelation> roomBedCheckRecordRelationList = roomBedCheckRecordRoomBedCheckRecordRelationMapper.selectList(Wrappers.lambdaQuery(RoomBedCheckRecordRelation.class).eq(RoomBedCheckRecordRelation::getRoomBedCheckRecordId, roomBedCheckRecord.getId()).select(RoomBedCheckRecordRelation::getId));
            List<Long> roomBedCheckRecordRelationIds = roomBedCheckRecordRelationList.stream().map(RoomBedCheckRecordRelation::getId).collect(Collectors.toList());
            //原有子表单 没有被删除的主键
            List<Long> roomBedCheckRecordRelationOldIds = roomBedCheckRecord.getRoomBedCheckRecordRelationList().stream().map(RoomBedCheckRecordRelation::getId).filter(Objects::nonNull).collect(Collectors.toList());
            //找到需要删除的id
            List<Long> roomBedCheckRecordRelationRemoveIds = roomBedCheckRecordRelationIds.stream().filter(item -> !roomBedCheckRecordRelationOldIds.contains(item)).collect(Collectors.toList());

            for (RoomBedCheckRecordRelation roomBedCheckRecordRelation : roomBedCheckRecord.getRoomBedCheckRecordRelationList()) {
                //如果不等于空则修改
                if (roomBedCheckRecordRelation.getId() != null) {
                    roomBedCheckRecordRoomBedCheckRecordRelationMapper.updateById(roomBedCheckRecordRelation);
                }
                //如果等于空 则新增
                else {
                    //已经不存在的id 删除
                    roomBedCheckRecordRelation.setRoomBedCheckRecordId(roomBedCheckRecord.getId());
                    roomBedCheckRecordRoomBedCheckRecordRelationMapper.insert(roomBedCheckRecordRelation);
                }
            }
            //已经不存在的id 删除
            if(roomBedCheckRecordRelationRemoveIds.size() > 0){
                roomBedCheckRecordRoomBedCheckRecordRelationMapper.deleteBatchIds(roomBedCheckRecordRelationRemoveIds);
            }
        }
        //********************************* RoomBedCheckRecordRelation  增删改  结束 *******************************************/

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delete(List<Long> ids) {
        roomBedCheckRecordRoomBedCheckRecordMapper.deleteBatchIds(ids);
        roomBedCheckRecordRoomBedCheckRecordRelationMapper.delete(Wrappers.lambdaQuery(RoomBedCheckRecordRelation.class).in(RoomBedCheckRecordRelation::getRoomBedCheckRecordId, ids));

        return true;
    }

    @Override
    public IPage<RoomBedCheckRecordPageVo> getPage(RoomBedCheckRecordPageDto dto) {
        MPJLambdaWrapper<RoomBedCheckRecord> queryRoomBedCheckRecord = new MPJLambdaWrapper<>();
        queryRoomBedCheckRecord
                .select(RoomBedCheckRecord::getId)
                .selectAs(XjrUser::getName,RoomBedCheckRecordPageVo::getUserIdCN)
                .selectAs(BaseClass::getName,RoomBedCheckRecordPageVo::getClassIdCN)
                .select(RoomBedCheckRecord.class,x -> VoToColumnUtil.fieldsToColumns(RoomBedCheckRecordPageVo.class).contains(x.getProperty()))
                .leftJoin(XjrUser.class,XjrUser::getId,RoomBedCheckRecord::getUserId)
                .leftJoin(BaseClass.class,BaseClass::getId,RoomBedCheckRecord::getClassId)
                .eq(ObjectUtil.isNotNull(dto.getClassId()), RoomBedCheckRecord::getClassId, dto.getClassId())
                .between(ObjectUtil.isNotNull(dto.getCheckRecordTimeStart()) && ObjectUtil.isNotNull(dto.getCheckRecordTimeEnd()), RoomBedCheckRecord::getCheckRecordTime, dto.getCheckRecordTimeStart(), dto.getCheckRecordTimeEnd())
                .disableSubLogicDel()
                .orderByDesc(RoomBedCheckRecord::getId);

        IPage<RoomBedCheckRecordPageVo> page = this.selectJoinListPage(ConventPage.getPage(dto), RoomBedCheckRecordPageVo.class, queryRoomBedCheckRecord);
        return page;
    }

    @Override
    public IPage<RoomBedCheckRecordPageVo> getPageMobile(RoomBedCheckRecordPageDto dto) {
        MPJLambdaWrapper<RoomBedCheckRecord> queryRoomBedCheckRecord = new MPJLambdaWrapper<>();
        queryRoomBedCheckRecord
                .select(RoomBedCheckRecord::getId)
                .selectAs(XjrUser::getName,RoomBedCheckRecordPageVo::getUserIdCN)
                .selectAs(BaseClass::getName,RoomBedCheckRecordPageVo::getClassIdCN)
                .select(RoomBedCheckRecord.class,x -> VoToColumnUtil.fieldsToColumns(RoomBedCheckRecordPageVo.class).contains(x.getProperty()))
                .leftJoin(XjrUser.class,XjrUser::getId,RoomBedCheckRecord::getUserId)
                .leftJoin(BaseClass.class,BaseClass::getId,RoomBedCheckRecord::getClassId)
                .eq(RoomBedCheckRecord::getUserId, StpUtil.getLoginIdAsLong())
                .eq(ObjectUtil.isNotNull(dto.getClassId()), RoomBedCheckRecord::getClassId, dto.getClassId())
                .between(ObjectUtil.isNotNull(dto.getCheckRecordTimeStart()) && ObjectUtil.isNotNull(dto.getCheckRecordTimeEnd()), RoomBedCheckRecord::getCheckRecordTime, dto.getCheckRecordTimeStart(), dto.getCheckRecordTimeEnd())
                .disableSubLogicDel()
                .orderByDesc(RoomBedCheckRecord::getId);

        IPage<RoomBedCheckRecordPageVo> page = this.selectJoinListPage(ConventPage.getPage(dto), RoomBedCheckRecordPageVo.class, queryRoomBedCheckRecord);
        return page;
    }

    @Override
    public RoomBedCheckRecordVo getInfo(Long id) {
        MPJLambdaWrapper<RoomBedCheckRecord> queryRoomBedCheckRecord = new MPJLambdaWrapper<>();
        queryRoomBedCheckRecord
                .select(RoomBedCheckRecord::getId)
                .selectAs(XjrUser::getName,RoomBedCheckRecordVo::getUserIdCN)
                .selectAs(BaseClass::getName,RoomBedCheckRecordVo::getClassIdCN)
                .select(RoomBedCheckRecord.class,x -> VoToColumnUtil.fieldsToColumns(RoomBedCheckRecordVo.class).contains(x.getProperty()))
                .leftJoin(XjrUser.class,XjrUser::getId,RoomBedCheckRecord::getUserId)
                .leftJoin(BaseClass.class,BaseClass::getId,RoomBedCheckRecord::getClassId)
                .eq(RoomBedCheckRecord::getId, id)
                .disableSubLogicDel()
                .orderByDesc(RoomBedCheckRecord::getId);

        RoomBedCheckRecordVo roomBedCheckRecordVo = this.selectJoinOne(RoomBedCheckRecordVo.class, queryRoomBedCheckRecord);
        if(roomBedCheckRecordVo == null){
            return null;
        }

        MPJLambdaWrapper<RoomBedCheckRecordRelation> queryRelation = new MPJLambdaWrapper<>();
        queryRelation
                .select(RoomBedCheckRecordRelation::getId)
                .selectAs(BaseOfficeBuild::getName,RoomBedCheckRecordRelationVo::getOfficeBuildIdCN)
                .select(RoomBedCheckRecordRelation.class,x -> VoToColumnUtil.fieldsToColumns(RoomBedCheckRecordRelationVo.class).contains(x.getProperty()))
                .leftJoin(BaseOfficeBuild.class, BaseOfficeBuild::getId, RoomBedCheckRecordRelation::getOfficeBuildId)
                .eq(RoomBedCheckRecordRelation::getRoomBedCheckRecordId,roomBedCheckRecordVo.getId())
                .orderByDesc(RoomBedCheckRecordRelation::getId);
        List<RoomBedCheckRecordRelationVo> roomBedCheckRecordRelationVoList = roomBedCheckRecordRoomBedCheckRecordRelationMapper.selectJoinList(RoomBedCheckRecordRelationVo.class, queryRelation);
        roomBedCheckRecordVo.setRoomBedCheckRecordRelationList(roomBedCheckRecordRelationVoList);

        roomBedCheckRecordVo.setFileList(fileService.list(Wrappers.<File>query().lambda().eq(File::getFolderId, roomBedCheckRecordVo.getFileId())));

        return roomBedCheckRecordVo;
    }

    @Override
    public RoomBedCheckRecordEchoVo getEcho() {
        //获取当前用户信息
        XjrUser xjrUser = xjrUserMapper.selectById(StpUtil.getLoginIdAsLong());
        RoomBedCheckRecordEchoVo roomBedCheckRecordEchoVo = new RoomBedCheckRecordEchoVo();
        roomBedCheckRecordEchoVo.setUserId(xjrUser.getId());
        roomBedCheckRecordEchoVo.setUserName(xjrUser.getName());

        //根据用户id获取其所管理的班级
        LambdaQueryWrapper<BaseClass> queryWrapperClass = new LambdaQueryWrapper<>();
        queryWrapperClass
                .eq(BaseClass::getTeacherId,xjrUser.getId());
        List<BaseClass> baseClassList = baseClassMapper.selectList(queryWrapperClass);
        List<BaseClass> classList = new ArrayList<>();
        List<Long> classIdList = new ArrayList<>();
        for (BaseClass baseClass : baseClassList) {
            classList.add(new BaseClass(){{
                setId(baseClass.getId());
                setName(baseClass.getName());
            }});
            classIdList.add(baseClass.getId());
        }
        roomBedCheckRecordEchoVo.setClassList(classList);

        //获取用户管理的寝室
        //根据班级
        List<RoomEchoVo> roomEchoVoByClassList = new ArrayList<>();
        if(classIdList != null && classIdList.size() > 0){
            MPJLambdaWrapper<Room> queryRoomByClass = new MPJLambdaWrapper<>();
            queryRoomByClass
                    .distinct()
                    .selectAs(Room::getId, RoomEchoVo::getRoomId)
                    .select("CONCAT(t3.name,\"-\" , t4.name, t.room_name) as roomName")
                    .leftJoin(RoomBed.class, RoomBed::getRoomId, Room::getId)
                    .leftJoin(BaseStudentSchoolRoll.class, BaseStudentSchoolRoll::getUserId, RoomBed::getStudentUserId)
                    .leftJoin(BaseOfficeBuild.class, BaseOfficeBuild::getId, Room::getOfficeBuildId)
                    .leftJoin(DictionaryDetail.class, DictionaryDetail::getCode, Room::getGender)
                    .in(BaseStudentSchoolRoll::getClassId, classIdList);
            roomEchoVoByClassList = roomMapper.selectJoinList(RoomEchoVo.class, queryRoomByClass);
        }

        //根据宿管任命
        MPJLambdaWrapper<Room> queryRoomByTeacherAppoint = new MPJLambdaWrapper<>();
        queryRoomByTeacherAppoint
                .distinct()
                .selectAs(Room::getId, RoomEchoVo::getRoomId)
                .select("CONCAT(t2.name,\"-\" , t3.name, t.room_name) as roomName")
                .leftJoin(RoomTeacherAppoint.class, RoomTeacherAppoint::getRoomId, Room::getId)
                .leftJoin(BaseOfficeBuild.class, BaseOfficeBuild::getId, Room::getOfficeBuildId)
                .leftJoin(DictionaryDetail.class, DictionaryDetail::getCode, Room::getGender)
                .eq(RoomTeacherAppoint::getUserId, StpUtil.getLoginIdAsLong())
                .disableSubLogicDel();
        List<RoomEchoVo> roomEchoVoByTeacherAppointList = roomMapper.selectJoinList(RoomEchoVo.class, queryRoomByTeacherAppoint);

        List<RoomEchoVo> roomEchoVoList = new ArrayList<>();
        roomEchoVoList.addAll(roomEchoVoByClassList);
        roomEchoVoList.addAll(roomEchoVoByTeacherAppointList);

        roomBedCheckRecordEchoVo.setRoomEchoVoList(roomEchoVoList);

        return roomBedCheckRecordEchoVo;
    }
}
