package com.yida.data.school.smart.service.impl;

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelReader;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yida.data.common.core.entity.CurrentUser;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.constant.FebsConstant;
import com.yida.data.common.core.entity.smart.EduSmartWelcomeDepartment;
import com.yida.data.common.core.entity.smart.EduSmartWelcomeGuideClassRecord;
import com.yida.data.common.core.entity.smart.EduSmartWelcomeGuideRoster;
import com.yida.data.common.core.entity.smart.EduSmartWelcomeGuideStepClass;
import com.yida.data.common.core.entity.smart.EduSmartWelcomeGuideStepClassFix;
import com.yida.data.common.core.entity.user.EduUserDept;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.FileUtil;
import com.yida.data.common.service.CommonService;
import com.yida.data.school.dto.smart.ClassFixImportDTO;
import com.yida.data.school.dto.smart.ClassImportDTO;
import com.yida.data.school.smart.excel.ExcelListener;
import com.yida.data.school.smart.mapper.EduSmartWelcomeGuideRosterMapper;
import com.yida.data.school.smart.mapper.EduSmartWelcomeGuideStepClassMapper;
import com.yida.data.school.smart.service.EduSmartWelcomeDepartmentService;
import com.yida.data.school.smart.service.EduSmartWelcomeGuideClassRecordService;
import com.yida.data.school.smart.service.EduSmartWelcomeGuideStepClassFixService;
import com.yida.data.school.smart.service.EduSmartWelcomeGuideStepClassService;
import com.yida.data.school.vo.smart.ClassFixImportVO;
import com.yida.data.school.vo.smart.ClassImportVO;
import com.yida.data.school.vo.smart.WelcomeImportProgress;
import com.yida.data.user.feign.RemoteUserDeptService;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;
import org.springframework.web.multipart.MultipartFile;

/**
 * 智慧迎新班级预分表Service实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class EduSmartWelcomeGuideStepClassServiceImpl extends ServiceImpl
    <EduSmartWelcomeGuideStepClassMapper, EduSmartWelcomeGuideStepClass> implements EduSmartWelcomeGuideStepClassService {

    private final RedisService redisService;
    private final EduSmartWelcomeGuideRosterMapper eduSmartWelcomeGuideRosterMapper;
    private final EduSmartWelcomeGuideClassRecordService eduSmartWelcomeGuideClassRecordService;
    private final EduSmartWelcomeGuideStepClassFixService eduSmartWelcomeGuideStepClassFixService;
    private final CommonService commonService;
    private final RemoteUserDeptService remoteUserDeptService;
    private final EduSmartWelcomeDepartmentService eduSmartWelcomeDepartmentService;
    @Value("${febs.uploadUrl}")
    private String uploadUrl;

    @Override
    public void downloadClassTemplate(HttpServletResponse response) {
        try {
            String fileName = "班级预选导入模板.xlsx";
            // 获取导入文件模板
            ClassPathResource classPathResource = new ClassPathResource("template/" + fileName);
            InputStream inputStream = classPathResource.getInputStream();
            com.yida.data.common.core.utils.FileUtil
                .download(com.yida.data.common.core.utils.FileUtil.inputStreamToFile(inputStream), fileName, false, response);
        } catch (Exception e) {
            throw new FebsException("下载班级预选导入模板失败");
        }
    }

    @Override
    public void downloadClassFixTemplate(HttpServletResponse response) {
        try {
            String fileName = "固定班级学生导入模板.xlsx";
            // 获取导入文件模板
            ClassPathResource classPathResource = new ClassPathResource("template/" + fileName);
            InputStream inputStream = classPathResource.getInputStream();
            com.yida.data.common.core.utils.FileUtil
                .download(com.yida.data.common.core.utils.FileUtil.inputStreamToFile(inputStream), fileName, false, response);
        } catch (Exception e) {
            throw new FebsException("固定班级学生导入模板模板失败");
        }
    }

    @Override
    public void importClassData(MultipartFile file, String importKey, CurrentUser currentUser) {
        // 错误信息文件excel
        File errorFile = null;
        try {
            // 验证文件类型
            if (!FileUtil.checkMultipartFile(file, FebsConstant.EXCEL_FILE_TYPE)) {
                return;
            }
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            // 调用导入方法
            ExcelListener<ClassImportDTO> listener = new ExcelListener<ClassImportDTO>();
            List<ClassImportDTO> listMap = new ArrayList<>();
            try {
                ExcelReader excelReader = EasyExcelFactory.read(file.getInputStream(), ClassImportDTO.class, listener)
                    .headRowNumber(1).build();
                excelReader.readAll();
                listMap = listener.getDatas();
                excelReader.finish();

            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            Integer current = 0;
            redisService.set(CachePrefixConstant.WELCOME_CLASS_IMPOST_PROGRESS + importKey,
                WelcomeImportProgress.<ClassImportVO>builder().importKey(importKey).total(listMap.size()).importStatus(0)
                    .current(0).build());

            List<ClassImportVO> classImportVOList = new ArrayList<>();
            List<EduUserDept> eduUserDeptList = remoteUserDeptService
                .findListByParent(-currentUser.getDeptId())
                .getData();
            List<EduSmartWelcomeDepartment> departmentList = eduSmartWelcomeDepartmentService.list();

            List<ClassImportDTO> errorList = new ArrayList<>();

            for (ClassImportDTO classImportDTO : listMap) {
                current++;
                redisService.set(CachePrefixConstant.WELCOME_CLASS_IMPOST_PROGRESS + importKey,
                    WelcomeImportProgress.builder().importKey(importKey).total(listMap.size()).current(current).importStatus(0)
                        .build());

                ClassImportVO vo = new ClassImportVO();
                BeanUtils.copyProperties(classImportDTO, vo);
                //学区ID
                List<EduUserDept> campusList = eduUserDeptList.stream()
                    .filter(dept -> dept.getDeptName().equals(vo.getCampusName()))
                    .collect(Collectors.toList());
                if (CollUtil.isEmpty(campusList)) {
                    errorList.add(classImportDTO);
                    continue;
                }
                Long campusId = campusList.get(0).getDeptId();
                //学段ID
                List<EduUserDept> sectionList = eduUserDeptList.stream()
                    .filter(dept -> dept.getDeptName().equals(vo.getSectionName()) &&
                        dept.getParentId().equals(campusId))
                    .collect(Collectors.toList());
                if (CollUtil.isEmpty(sectionList)) {
                    errorList.add(classImportDTO);
                    continue;
                }
                Long sectionId = sectionList.get(0).getDeptId();
                //年级ID
                List<EduUserDept> gradeList = eduUserDeptList.stream()
                    .filter(dept -> dept.getDeptName().equals(vo.getGradeName()) &&
                        dept.getParentId().equals(sectionId))
                    .collect(Collectors.toList());
                if (CollUtil.isEmpty(gradeList)) {
                    errorList.add(classImportDTO);
                    continue;
                }
                Long gradeId = gradeList.get(0).getDeptId();
                //班级ID
                List<EduUserDept> classList = eduUserDeptList.stream()
                    .filter(dept -> dept.getDeptName().equals(vo.getClassName()) &&
                        dept.getParentId().equals(gradeId))
                    .collect(Collectors.toList());
                if (CollUtil.isEmpty(classList)) {
                    errorList.add(classImportDTO);
                    continue;
                }
                Long classId = classList.get(0).getDeptId();
                //系部ID
                List<EduSmartWelcomeDepartment> departmentList1 = departmentList.stream()
                    .filter(d -> d.getName().equals(vo.getDepartmentName()))
                    .collect(Collectors.toList());
                if (CollUtil.isEmpty(departmentList1)) {
                    errorList.add(classImportDTO);
                    continue;
                }
                Long departmentId = departmentList1.get(0).getId();
                //专业ID
                List<EduSmartWelcomeDepartment> majorList = departmentList.stream()
                    .filter(d -> d.getName().equals(vo.getMajorName()))
                    .collect(Collectors.toList());
                if (CollUtil.isEmpty(majorList)) {
                    errorList.add(classImportDTO);
                    continue;
                }
                Long majorId = majorList.get(0).getId();

                vo.setCampusId(campusId);
                vo.setSectionId(sectionId);
                vo.setGradeId(gradeId);
                vo.setClassId(classId);
                vo.setDepartmentId(departmentId);
                vo.setMajorId(majorId);

                classImportVOList.add(vo);
            }
            WelcomeImportProgress<ClassImportVO> build = WelcomeImportProgress.<ClassImportVO>builder().importKey(importKey)
                .total(listMap.size()).current(listMap.size())
                .importStatus(1)
                .dataList(classImportVOList).build();

            if (CollUtil.isNotEmpty(errorList)) {
                // 错误信息文件名称
                String fileName = FileUtil.getLocalUploadAddress() + UUID.randomUUID() + ".xlsx";
                EasyExcel.write(fileName, ClassImportDTO.class)
                    .sheet("错误信息")
                    .doWrite(errorList);
                // 上传到媒资
                errorFile = new File(fileName);
                String url = FileUtil.uploadFileToMediaServer(uploadUrl, errorFile);
                build.setErrorPath(url);
                build.setImportStatus(2);
            }

            redisService.set(CachePrefixConstant.WELCOME_CLASS_IMPOST_PROGRESS + importKey, build);
            stopWatch.stop();
            log.info("导入班级预分数据总共耗时: {}", stopWatch.getTotalTimeSeconds() + "秒");
        } catch (Exception e) {
            log.error("导入指预选班级数据失败: {}", e.getMessage(), e);
            redisService.set(CachePrefixConstant.WELCOME_CLASS_IMPOST_PROGRESS + importKey,
                WelcomeImportProgress.<ClassImportVO>builder().importKey(importKey)
                    .total(100).current(100)
                    .importStatus(2).build());
            throw new FebsException("导入失败！请重新操作");
        } finally {
            if (Objects.nonNull(errorFile)) {
                cn.hutool.core.io.FileUtil.del(errorFile);
            }
        }
    }

    @Override
    public ClassFixImportVO importClassFixData(MultipartFile file, CurrentUser currentUser, Long guideId) {
        // 验证文件类型
        if (!FileUtil.checkMultipartFile(file, FebsConstant.EXCEL_FILE_TYPE)) {
            return null;
        }
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        ClassFixImportVO classFixImportVO = new ClassFixImportVO();
        List<ClassFixImportVO.FixImportVO> voList = new ArrayList<>();
        // 调用导入方法
        ExcelListener<ClassFixImportDTO> listener = new ExcelListener<ClassFixImportDTO>();
        try {
            ExcelReader excelReader = EasyExcelFactory.read(file.getInputStream(), ClassFixImportDTO.class, listener)
                .headRowNumber(1).build();
            excelReader.readAll();
            List<ClassFixImportDTO> listMap = listener.getDatas();
            List<String> errorIdNumberList = new ArrayList<>();
            excelReader.finish();
            List<EduUserDept> eduUserDeptList = remoteUserDeptService
                .findListByParent(-currentUser.getDeptId())
                .getData();
            List<EduSmartWelcomeGuideRoster> eduSmartWelcomeGuideRosters = eduSmartWelcomeGuideRosterMapper
                .selectList(Wrappers.lambdaQuery(new EduSmartWelcomeGuideRoster())
                    .eq(EduSmartWelcomeGuideRoster::getGuideId, guideId));

            for (ClassFixImportDTO classFixImportDTO : listMap) {
                ClassFixImportVO.FixImportVO vo = new ClassFixImportVO().new FixImportVO();
                BeanUtils.copyProperties(classFixImportDTO, vo);

                //学区ID
                List<EduUserDept> campusList = eduUserDeptList.stream()
                    .filter(dept -> dept.getDeptName().equals(vo.getCampusName()))
                    .collect(Collectors.toList());
                if (CollUtil.isEmpty(campusList)) {
                    errorIdNumberList.add(classFixImportDTO.getIdNumber());
                    continue;
                }
                Long campusId = campusList.get(0).getDeptId();
                //学段ID
                List<EduUserDept> sectionList = eduUserDeptList.stream()
                    .filter(dept -> dept.getDeptName().equals(vo.getSectionName()) &&
                        dept.getParentId().equals(campusId))
                    .collect(Collectors.toList());
                if (CollUtil.isEmpty(sectionList)) {
                    errorIdNumberList.add(classFixImportDTO.getIdNumber());
                    continue;
                }
                Long sectionId = sectionList.get(0).getDeptId();
                //年级ID
                List<EduUserDept> gradeList = eduUserDeptList.stream()
                    .filter(dept -> dept.getDeptName().equals(vo.getGradeName()) &&
                        dept.getParentId().equals(sectionId))
                    .collect(Collectors.toList());
                if (CollUtil.isEmpty(gradeList)) {
                    errorIdNumberList.add(classFixImportDTO.getIdNumber());
                    continue;
                }
                Long gradeId = gradeList.get(0).getDeptId();
                //班级ID
                List<EduUserDept> classList = eduUserDeptList.stream()
                    .filter(dept -> dept.getDeptName().equals(vo.getClassName()) &&
                        dept.getParentId().equals(gradeId))
                    .collect(Collectors.toList());
                if (CollUtil.isEmpty(classList)) {
                    errorIdNumberList.add(classFixImportDTO.getIdNumber());
                    continue;
                }
                Long classId = classList.get(0).getDeptId();

                List<EduSmartWelcomeGuideRoster> rosters = eduSmartWelcomeGuideRosters.stream()
                    .filter(g -> g.getFullName().equals(classFixImportDTO.getRosterName())).collect(Collectors.toList());

                if (CollUtil.isEmpty(rosters)) {
                    errorIdNumberList.add(classFixImportDTO.getIdNumber());
                    continue;
                }
                Long rosterId = rosters.get(0).getId();

                vo.setCampusId(campusId);
                vo.setSectionId(sectionId);
                vo.setGradeId(gradeId);
                vo.setClassId(classId);
                vo.setRosterId(rosterId);
                voList.add(vo);
            }

            if (CollUtil.isNotEmpty(errorIdNumberList)) {
                classFixImportVO.setErrorIdNumberList(errorIdNumberList);
            }

            if (CollUtil.isNotEmpty(voList)) {
                classFixImportVO.setFixImportVOList(voList);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        stopWatch.stop();
        log.info("导入固定班级学生数据总共耗时: {}", stopWatch.getTotalTimeSeconds() + "秒");
        return classFixImportVO;
    }

    @Override
    public void classBanding(Long guideId, Long stepId, Long rosterId) {
        //比对专业查找出对应的班级
        Long schoolId = null;
        Long campusId = null;
        Long sectionId = null;
        Long gradeId = null;
        Long classId = null;

        EduSmartWelcomeGuideRoster roster = (EduSmartWelcomeGuideRoster) redisService
            .hget(CachePrefixConstant.WELCOME_ROSTER, rosterId.toString());
        if (ObjectUtil.isNull(roster)) {
            roster = eduSmartWelcomeGuideRosterMapper.selectById(rosterId);
        }

        if (ObjectUtil.isNull(roster)) {
            log.info("花名册无人员信息：【{}】", rosterId);
            return;
        }
        //排除固定班级里面学生
        List<EduSmartWelcomeGuideStepClassFix> fixRosterList = eduSmartWelcomeGuideStepClassFixService
            .list(Wrappers.lambdaQuery(new EduSmartWelcomeGuideStepClassFix())
                .eq(EduSmartWelcomeGuideStepClassFix::getRosterId, rosterId));
        if (CollUtil.isNotEmpty(fixRosterList)) {
            log.info("花名册人员【{}】已在固定班级【{}】", roster.getFullName(), fixRosterList.get(0).getClassId());
            schoolId = fixRosterList.get(0).getSchoolId();
            campusId = fixRosterList.get(0).getCampusId();
            sectionId = fixRosterList.get(0).getSectionId();
            gradeId = fixRosterList.get(0).getGradeId();
            classId = fixRosterList.get(0).getClassId();
        } else {
            //查询预分班级信息
            List<EduSmartWelcomeGuideStepClass> classList = new ArrayList<>();
            String str = (String) redisService.get(CachePrefixConstant.WELCOME_CLASS_DATA + guideId + stepId);
            if (ObjectUtil.isNotNull(str)) {
                classList = JSON.parseArray(str, EduSmartWelcomeGuideStepClass.class);
            } else {
                classList = this.list(Wrappers.lambdaQuery(new EduSmartWelcomeGuideStepClass())
                    .eq(EduSmartWelcomeGuideStepClass::getGuideId, guideId)
                    .eq(EduSmartWelcomeGuideStepClass::getStepId, stepId));

                if (CollUtil.isNotEmpty(classList)) {
                    redisService
                        .set(CachePrefixConstant.WELCOME_CLASS_DATA + guideId + stepId, JSONObject.toJSON(classList).toString());
                }
            }
            if (CollUtil.isEmpty(classList)) {
                log.info("无预分班级信息：guideId=【{}】", guideId);
                return;
            }
            //当前校区系部专业对应的班级
            EduSmartWelcomeGuideRoster finalRoster = roster;

            List<EduSmartWelcomeGuideStepClass> departMajorClassList = classList.stream()
                .filter(c -> c.getDepartmentId().equals(finalRoster.getAdmittedDepartmentId()) && c.getMajorId()
                    .equals(finalRoster.getAdmittedMajorId()))
                .collect(
                    Collectors.toList());

            for (EduSmartWelcomeGuideStepClass eduSmartWelcomeGuideStepClass : departMajorClassList) {
                String key = ObjectUtil.equals(0, roster.getGender()) ? "male:" : "female:";
                if (redisService
                    .hHasKey(CachePrefixConstant.WELCOME_CLASS_STUDENT_NUMBER, key + eduSmartWelcomeGuideStepClass.getId())) {
                    Integer number = (Integer) redisService
                        .hget(CachePrefixConstant.WELCOME_CLASS_STUDENT_NUMBER, key + eduSmartWelcomeGuideStepClass.getId());
                    Integer planNumber = ObjectUtil.equals(0, roster.getGender()) ? eduSmartWelcomeGuideStepClass.getMaleNumber()
                        : eduSmartWelcomeGuideStepClass.getFemaleNumber();
                    if (number >= planNumber) {
                        continue;
                    }
                }
                //分配学生到此班级
                //人数+1
                redisService
                    .hincr(CachePrefixConstant.WELCOME_CLASS_STUDENT_NUMBER, key + eduSmartWelcomeGuideStepClass.getId(), 1D);
                //填充数据库数据
                if (ObjectUtil.equals(0, roster.getGender())) { //男
                    baseMapper.incrMale(eduSmartWelcomeGuideStepClass.getId());
                } else {
                    baseMapper.incrFemale(eduSmartWelcomeGuideStepClass.getId());
                }

                schoolId = eduSmartWelcomeGuideStepClass.getSchoolId();
                campusId = eduSmartWelcomeGuideStepClass.getCampusId();
                sectionId = eduSmartWelcomeGuideStepClass.getSectionId();
                gradeId = eduSmartWelcomeGuideStepClass.getGradeId();
                classId = eduSmartWelcomeGuideStepClass.getClassId();

                log.info("学生【{}】分配到【{}】班级", roster.getFullName(), eduSmartWelcomeGuideStepClass.getClassId());
                break;
            }
        }
        if (ObjectUtil.isNotNull(schoolId) && ObjectUtil.isNotNull(campusId) && ObjectUtil.isNotNull(sectionId) && ObjectUtil
            .isNotNull(gradeId) && ObjectUtil.isNotNull(classId)) {

            //增加分班记录
            EduSmartWelcomeGuideClassRecord classRecord = new EduSmartWelcomeGuideClassRecord();
            classRecord.setSchoolId(schoolId);
            classRecord.setCampusId(campusId);
            classRecord.setSectionId(sectionId);
            classRecord.setGradeId(gradeId);
            classRecord.setClassId(classId);
            classRecord.setRosterId(rosterId);
            classRecord.setGuideId(guideId);
            eduSmartWelcomeGuideClassRecordService.save(classRecord);

            //填充花名册数据
            roster.setCampusId(campusId);
            roster.setCampusName(commonService.getUserDept(campusId).getDeptName());
            roster.setSectionId(sectionId);
            roster.setSectionName(commonService.getUserDept(sectionId).getDeptName());
            roster.setGradeId(gradeId);
            roster.setGradeName(commonService.getUserDept(gradeId).getDeptName());
            roster.setClassId(classId);
            roster.setClassName(commonService.getUserDept(classId).getDeptName());
            eduSmartWelcomeGuideRosterMapper.updateById(roster);
        }
    }
}
