package com.yida.data.user.service.impl;

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.school.EduDormitoryRoom;
import com.yida.data.common.core.entity.user.EduStudent;
import com.yida.data.common.core.entity.user.EduUserDept;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.Asserts;
import com.yida.data.common.core.utils.ExcelUtil;
import com.yida.data.common.core.vo.ImportPercentVO;
import com.yida.data.common.service.CommonService;
import com.yida.data.school.dto.index.EditPersonNumDTO;
import com.yida.data.school.dto.index.ListDormRoomDTO;
import com.yida.data.school.feign.facility.RemoteDormitoryService;
import com.yida.data.user.config.ExportStudentDormClient;
import com.yida.data.user.dto.ExchangeDormDTO;
import com.yida.data.user.dto.ImportStudentDormDTO;
import com.yida.data.user.dto.PageStudentDormDTO;
import com.yida.data.user.excel.SelectStudentDormExportData;
import com.yida.data.user.excel.SelectStudentExportData;
import com.yida.data.user.listener.ImportStudentDormListener;
import com.yida.data.user.mapper.EduStudentMapper;
import com.yida.data.user.service.EduStudentDormService;
import com.yida.data.user.service.EduUserDeptService;
import com.yida.data.user.vo.StudentDormInfoVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class EduStudentDormServiceImpl implements EduStudentDormService {

    private final EduStudentMapper eduStudentMapper;
    private final RemoteDormitoryService remoteDormitoryService;

    private final RedisService redisService;

    private final EduUserDeptService eduUserDeptService;

    @Lazy
    @Resource
    private ExportStudentDormClient exportStudentDormClient;

    @Override
    public IPage<StudentDormInfoVO> listStudentDormPage(PageStudentDormDTO dto) {
        List<Long> dormIds = new ArrayList<>();
        Map<Long, List<EduDormitoryRoom>> dormRoomGroup = new HashMap<>();
        // 查询匹配的宿舍
        if (dto.getDormRoomId() == null) {
            List<EduDormitoryRoom> dormRooms = remoteDormitoryService.listDormRoom(ListDormRoomDTO.builder()
                .schoolId(dto.getSchoolId())
                .floor(dto.getFloor())
                .dormIds(dto.getDormId() != null ? Collections.singletonList(dto.getDormId()) : null).build()).getData();
            if (CollUtil.isNotEmpty(dormRooms)) {
                dormRoomGroup = dormRooms.stream().collect(Collectors.groupingBy(EduDormitoryRoom::getDormId));
                dormIds = dormRooms.stream().map(EduDormitoryRoom::getId).collect(Collectors.toList());
            }
        } else {
            dormIds = Collections.singletonList(dto.getDormRoomId());
        }
        // 宿舍为空 不查询数据
        if (CollUtil.isEmpty(dormIds)) {
            dormIds = new ArrayList<>();
            dormIds.add(-1L);
        }
        IPage<StudentDormInfoVO> page = eduStudentMapper.listStudentDormPage(dto.toPage(), dormIds, dto);
        if (CollUtil.isNotEmpty(page.getRecords())) {
            for (StudentDormInfoVO record : page.getRecords()) {
                // 年级班级信息
                EduUserDept grade = this.eduUserDeptService.getById(record.getGradeId());
                EduUserDept clazz = this.eduUserDeptService.getById(record.getClassId());
                StringBuilder gradeClass = new StringBuilder();
                if (grade != null) {
                    gradeClass.append(grade.getDeptName());
                }
                if (clazz != null) {
                    gradeClass.append(clazz.getDeptName());
                }
                record.setGradeClass(gradeClass.toString());
                log.info("record:{}", record);
                // 入住寝室信息
                EduDormitoryRoom dormRoom = null;
                if (CollUtil.isNotEmpty(dormRoomGroup) && dormRoomGroup.containsKey(record.getDormRoomId())) {
                    dormRoom = dormRoomGroup.get(record.getDormRoomId()).get(0);
                } else {
                    dormRoom = remoteDormitoryService.getDormRoom(record.getDormRoomId()).getData();
                    if (dormRoom != null) {
                        dormRoomGroup.put(dormRoom.getId(), Collections.singletonList(dormRoom));
                    }
                }
                // 查询到了寝室信息
                if (dormRoom != null) {
                    String dormRoomName = dormRoom.getDormName() +
                            dormRoom.getFloor() + "层" +
                            dormRoom.getName();
                    record.setDormRoomName(dormRoomName);
                }
            }
        }
        return page;
    }

    @Override
    public void saveStudentDorm(Long studentId, Long dormRoomId, Long dormId) {
        EduDormitoryRoom dormRoom = remoteDormitoryService.getDormRoomNoPermission(dormRoomId).getData();
        // 满员
        Asserts.isTrue(dormRoom.getCheckInNum() < dormRoom.getBedNum(), "该宿舍已满员");
        EduStudent student = new EduStudent();
        student.setCheckInTime(LocalDateTime.now());
        student.setId(studentId);
        student.setDormRoomId(dormRoomId);
        student.setDormId(dormId);
        eduStudentMapper.updateById(student);
        // 添加
        EditPersonNumDTO dto = new EditPersonNumDTO();
        dto.setDormRoomId(dormRoomId);
        dto.setNum(1);
        remoteDormitoryService.editPersonNum(Arrays.asList(dto));
    }

    @Override
    public void cancelBatch(List<Long> studentIds) {
        if (CollUtil.isNotEmpty(studentIds)) {
            List<EduStudent> students = eduStudentMapper.selectBatchIds(studentIds);
            Map<Long, EditPersonNumDTO> dtoMap = new HashMap<>();
            // 构建每一个寝室要更改的人数
            for (EduStudent student : students) {
                Asserts.isNotNull(student, String.format("学生%s不存在", student.getStuName()));
                Asserts.isTrue(student.getDormRoomId() != null, String.format("学生%s不存在宿舍", student.getStuName()));
                if (!dtoMap.containsKey(student.getDormRoomId())) {
                    EditPersonNumDTO dto = new EditPersonNumDTO();
                    dto.setDormRoomId(student.getDormRoomId());
                    dto.setNum(0);
                    dtoMap.put(student.getDormRoomId(), dto);
                }
                EditPersonNumDTO dto = dtoMap.get(student.getDormRoomId());
                dto.setNum(dto.getNum() - 1);
            }
            //List<Long> roomIds = students.stream().map(x -> x.getDormRoomId()).collect(Collectors.toList());
            eduStudentMapper.update(null, Wrappers.<EduStudent>lambdaUpdate()
                .in(EduStudent::getId, studentIds)
                .set(EduStudent::getDormRoomId, null)
                .set(EduStudent::getDormId, null));
            // 添加
            remoteDormitoryService.editPersonNum(dtoMap.values().stream().collect(Collectors.toList()));
        }
    }

    @Override
    public void exchangeDorm(ExchangeDormDTO dto) {
        EduStudent student = eduStudentMapper.selectById(dto.getStudentId());
        if (dto.getTargetStudentId() != null) {
            EduStudent targetStudent = eduStudentMapper.selectById(dto.getTargetStudentId());
            // 相互交换寝室
            eduStudentMapper.update(null, Wrappers.<EduStudent>lambdaUpdate()
                .eq(EduStudent::getId, dto.getStudentId())
                .set(EduStudent::getDormRoomId, targetStudent.getDormRoomId())
                .set(EduStudent::getDormId, targetStudent.getDormId())
                .set(EduStudent::getCheckInTime, LocalDateTime.now()));
            eduStudentMapper.update(null, Wrappers.<EduStudent>lambdaUpdate()
                .eq(EduStudent::getId, dto.getTargetStudentId())
                .set(EduStudent::getDormRoomId, student.getDormRoomId())
                .set(EduStudent::getDormId, student.getDormId())
                .set(EduStudent::getCheckInTime, LocalDateTime.now()));
        } else if (dto.getTargetDormId() != null) {
            eduStudentMapper.update(null, Wrappers.<EduStudent>lambdaUpdate()
                .eq(EduStudent::getId, dto.getStudentId())
                .set(EduStudent::getDormRoomId, dto.getTargetDormRoomId())
                .set(EduStudent::getDormId, dto.getTargetDormId())
                .set(EduStudent::getCheckInTime, LocalDateTime.now()));
            // 添加新寝室  删除原寝室
            EditPersonNumDTO editNew = new EditPersonNumDTO();
            EditPersonNumDTO editOld = new EditPersonNumDTO();
            editNew.setDormRoomId(dto.getTargetDormRoomId());
            editNew.setNum(1);
            editOld.setDormRoomId(student.getDormRoomId());
            editOld.setNum(-1);
            remoteDormitoryService.editPersonNum(Arrays.asList(editNew, editOld));
        }
    }

    @Override
    public void importDormRoom(MultipartFile file, Long schoolId, String key) {
        ImportPercentVO percent =
            (ImportPercentVO) redisService.hget(CachePrefixConstant.IMPORT_STUDENT_DORM, key);
        Asserts.isTrue(percent == null || percent.getFinish() == 1, "有文件正在导入，请稍后重试");
        try {
            int rowNum = ExcelUtil.readExcel(file.getInputStream(), "xlsx").getSheetAt(0).getLastRowNum();
            ImportPercentVO percentVO = new ImportPercentVO();
            percentVO.setTotal(Long.valueOf(rowNum));
            EasyExcel.read(file.getInputStream(), ImportStudentDormDTO.class,
                new ImportStudentDormListener(redisService, eduStudentMapper, remoteDormitoryService, percentVO, schoolId,
                    key)).sheet().doRead();
        } catch (IOException e) {
            log.error("导入失败", e);
            throw new FebsException("导入失败");
        }
    }

    @Override
    public void exportStudentDorm(PageStudentDormDTO dto, String key) {
        SelectStudentDormExportData data = new SelectStudentDormExportData();
        BeanUtils.copyProperties(dto, data);
        data.setKey(key);
        data.setFunctionName("学生宿舍导出");
        exportStudentDormClient.exportExcelData(data);
    }

    @Override
    public Object getStudentDormExportInfo(String key) {
        return exportStudentDormClient.selectExportInfo(key);
    }
}
 