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

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yida.data.attendance.dto.IssuedFaceDTO;
import com.yida.data.attendance.feign.RemoteAttendanceDeviceService;
import com.yida.data.common.core.entity.CurrentUser;
import com.yida.data.common.core.entity.Dict;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.system.Dept;
import com.yida.data.common.core.entity.system.enums.RoleEnum;
import com.yida.data.common.core.entity.user.EduStudent;
import com.yida.data.common.core.entity.user.EduStudentApply;
import com.yida.data.common.core.entity.user.EduUserDept;
import com.yida.data.common.core.entity.user.EduUserDevice;
import com.yida.data.common.core.entity.user.EduUserFace;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.FebsUtil;
import com.yida.data.common.core.utils.FileUtil;
import com.yida.data.common.service.CommonService;
import com.yida.data.school.dto.transaction.ListApplyFunctionDTO;
import com.yida.data.system.feign.RemoteDeptService;
import com.yida.data.user.dto.ListStudentApplyDTO;
import com.yida.data.user.dto.ListStudentDTO;
import com.yida.data.user.feign.RemoteStudentService;
import com.yida.data.user.listener.importStudentApplyListener;
import com.yida.data.user.mapper.EduStudentApplyMapper;
import com.yida.data.user.mapper.EduUserDeviceMapper;
import com.yida.data.user.service.EduStudentApplyService;
import com.yida.data.user.service.EduStudentService;
import com.yida.data.user.service.EduUserDeptService;
import com.yida.data.user.service.EduUserFaceService;
import com.yida.data.user.vo.StudentApplyImportErrorVO;
import com.yida.data.user.vo.StudentApplyImportProgressVO;
import com.yida.data.user.vo.StudentApplyImportVO;
import com.yida.data.user.vo.StudentApplyStatusVO;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;
import org.springframework.web.multipart.MultipartFile;

@Slf4j
@Service
@RequiredArgsConstructor
public class EduStudentApplyServiceImpl extends ServiceImpl<EduStudentApplyMapper, EduStudentApply> implements
    EduStudentApplyService {

    private final CommonService commonService;

    private final RedisService redisService;

    private final RemoteStudentService remoteStudentService;

    private final RemoteDeptService remoteDeptService;

    private final EduUserDeptService eduUserDeptService;

    private final EduStudentService eduStudentService;

    private final EduUserFaceService eduUserFaceService;

    private final EduUserDeviceMapper eduUserDeviceMapper;

    private final RemoteAttendanceDeviceService remoteAttendanceDeviceService;

    @Value("${febs.uploadUrl}")
    private String uploadUrl;

    @Override
    public StudentApplyStatusVO getStudentApplyStatus(Long studentId, String applyCode) {
        StudentApplyStatusVO applyStatus = new StudentApplyStatusVO();
        List<EduStudentApply> list = list(Wrappers.lambdaQuery(new EduStudentApply()).eq(EduStudentApply::getStudentId,
            studentId)
            .eq(EduStudentApply::getApplyCode, applyCode)
            .ge(EduStudentApply::getEndTime, LocalDateTime.now())
            .le(EduStudentApply::getStartTime, LocalDateTime.now()));
        if (CollUtil.isEmpty(list)) {
            List<EduStudentApply> applyList = baseMapper.getStudentApplyStatus(studentId, applyCode);
            if (CollUtil.isNotEmpty(applyList)) {
                applyStatus.setStatus(2);
                applyStatus.setDeadLine(applyList.get(0).getEndTime().toLocalDate().plusDays(1L));
            } else {
                applyStatus.setStatus(0);
            }
        } else {
            applyStatus.setStatus(1);
        }
        return applyStatus;
    }

    @Override
    public IPage<EduStudentApply> listStudentApply(ListStudentApplyDTO dto, Page<EduStudentApply> page) {
        List<Long> schoolIds = new ArrayList<>();
        CurrentUser currentUser = FebsUtil.getCurrentUser();
        if (currentUser.getRolePerms().contains(RoleEnum.ROLE_SCHOOL_PRINCIPAL.getValue())) {
            schoolIds = Collections.singletonList(currentUser.getDeptId());
        } else {
            schoolIds = remoteDeptService.getSchoolByArea(null, null).getData().stream().map(Dept::getDeptId)
                .collect(Collectors.toList());
        }
        dto.setSchoolIdList(schoolIds);
        IPage<EduStudentApply> eduStudentApplyIPage = this.baseMapper.listStudentApply(dto, page);
        return eduStudentApplyIPage;
    }

    @Override
    public void saveStudentApply(EduStudentApply eduStudentApply) {
        eduStudentApply.setApplyName(
            commonService.getDictByTypeAndValueOrLabel("apply_type", eduStudentApply.getApplyCode(), null).getLabel());
        eduStudentApply.setStudentName(eduStudentService.getById(eduStudentApply.getStudentId()).getStuName());
        eduStudentApply.setStudentNumber(eduStudentService.getById(eduStudentApply.getStudentId()).getStuNumber());
        eduStudentApply.setSchoolName(commonService.getDept(eduStudentApply.getSchoolId()).getDeptName());
        eduStudentApply.setCampusName(eduUserDeptService.getById(eduStudentApply.getCampusId()).getDeptName());
        eduStudentApply.setSectionName(eduUserDeptService.getById(eduStudentApply.getSectionId()).getDeptName());
        eduStudentApply.setGradeName(eduUserDeptService.getById(eduStudentApply.getGradeId()).getDeptName());
        eduStudentApply.setClassName(eduUserDeptService.getById(eduStudentApply.getClassId()).getDeptName());
        this.save(eduStudentApply);

        //编辑再次下发人脸
        UpdateUserToHaiQing(eduStudentApply);

    }


    /**
     * 更新面板机会员
     *
     * @param eduStudentApply
     */
    public void UpdateUserToHaiQing(EduStudentApply eduStudentApply) {
        EduUserFace userFace = eduUserFaceService.getOne(
            Wrappers.lambdaQuery(new EduUserFace()).eq(EduUserFace::getUserId, eduStudentApply.getStudentId())
                .eq(EduUserFace::getUserType, 0));
        if (userFace == null) {
            userFace = new EduUserFace();
            userFace.setUserId(eduStudentApply.getStudentId());
            userFace.setName(eduStudentApply.getStudentName());
            userFace.setUserType(0);

            EduStudent student = (EduStudent) redisService.hget(CachePrefixConstant.STUDENT_DATA,
                eduStudentApply.getStudentId().toString());
            if (student == null) {
                student = eduStudentService.getStudent(eduStudentApply.getStudentId());
            }
            if (ObjectUtil.isNull(student) || ObjectUtil.isNull(student.getAvatar())) {
                log.info("无匹配学生信息或者导入学生信息无头像，无法下发 === {}", student.getId());
                return;
            }
        }
        userFace.setNotes(1);
        userFace.setCardValidBegin(eduStudentApply.getStartTime().toString());
        userFace.setCardValidEnd(eduStudentApply.getEndTime().toString());
        eduUserFaceService.saveOrUpdate(userFace);
        //用户原来存在的设备
        List<EduUserDevice> userDeviceList = eduUserDeviceMapper.selectList(
            Wrappers.lambdaQuery(new EduUserDevice()).eq(EduUserDevice::getUserId, eduStudentApply.getStudentId())
                .eq(EduUserDevice::getUserType, 0));
        if (CollUtil.isNotEmpty(userDeviceList)) {
            // 用户已经被下发到设备，更新设备上的图像
            Map<Long, List<EduUserDevice>> userDeviceMap = userDeviceList.stream().collect(
                Collectors.groupingBy(EduUserDevice::getFaceGroupId));
            for (Map.Entry<Long, List<EduUserDevice>> entry : userDeviceMap.entrySet()) {
                Long faceGroupId = entry.getKey();
                List<EduUserDevice> eduUserDevices = entry.getValue();
                // 设备id
                List<Long> deviceIds = eduUserDevices.stream().map(EduUserDevice::getDeviceId).distinct()
                    .collect(Collectors.toList());
                IssuedFaceDTO dto = new IssuedFaceDTO();
                dto.setDeviceList(deviceIds);
                dto.setGroupId(faceGroupId);
                dto.setUserFaceList(Collections.singletonList(userFace));
                remoteAttendanceDeviceService.issuedFace(dto);
            }
        }
    }

    @Override
    public void downloadTemplate(HttpServletResponse response) throws Exception {

        String fileName = "学生开通应用导入模板.xls";
        // 获取导入文件模板
        ClassPathResource classPathResource = new ClassPathResource("template/" + fileName);
        InputStream inputStream = classPathResource.getInputStream();
        FileUtil.download(FileUtil.inputStreamToFile(inputStream), fileName, false, response);
    }

    @Override
    public void importStudentApplyInfo(MultipartFile file, String redisKey) throws IOException {
        log.info("开始导入学生开通应用数据");
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        EasyExcel.read(file.getInputStream(), StudentApplyImportVO.class,
            new importStudentApplyListener(this, redisKey))
            .sheet(0).headRowNumber(1).doRead();
        stopWatch.stop();
        log.info("导入学生开通应用数据总共耗时: {}", stopWatch.getTotalTimeSeconds() + "秒");
    }

    @Override
    public void insertStudentApplyData(List<StudentApplyImportVO> studentApplyImportVOList, String redisKey) {
        StudentApplyImportProgressVO progressVO = new StudentApplyImportProgressVO();
        progressVO.setFinish(0);
        progressVO.setTotalNum(studentApplyImportVOList.size());
        progressVO.setCurrentNum(0);
        progressVO.setRedisKey(redisKey);
        redisService.hset(CachePrefixConstant.IMPORT_STUDENT_APPLY_PROGRESS, redisKey, progressVO);

        List<StudentApplyImportErrorVO> errorVOList = new ArrayList<>();
        List<EduStudentApply> saveData = new ArrayList<>();
        Integer index = 1;

        for (StudentApplyImportVO studentApplyImportVO : studentApplyImportVOList) {
            index++;
            String baseMag = "第" + index + "行，";
            StudentApplyImportErrorVO studentApplyImportErrorVO = checkImportDataIsNull(index, studentApplyImportVO);
            if (studentApplyImportErrorVO != null) {
                progressVO.setCurrentNum(index - 1);
                errorVOList.add(studentApplyImportErrorVO);
                continue;
            }
            Dept dept = commonService.getSchoolByName(studentApplyImportVO.getSchoolName());
            if (ObjectUtil.isNull(dept)) {
                StudentApplyImportErrorVO errorVO = new StudentApplyImportErrorVO();
                errorVO.setErrorMsg(baseMag + "学校名称不匹配");
                errorVOList.add(errorVO);
                progressVO.setCurrentNum(index - 1);
                continue;
            }
            // 根据学校ID、学号查询学生信息  检测学号与学生姓名是否匹配
            EduStudent student = new EduStudent();
            student.setSchoolId(dept.getDeptId());
            student.setStuNumber(studentApplyImportVO.getStudentNumber());
            List<EduStudent> currentStudentList = remoteStudentService.listBaseStudentNoJoin(student).getData();
            EduStudentApply eduStudentApply = new EduStudentApply();
            eduStudentApply.setCampusName(studentApplyImportVO.getCampusName());
            eduStudentApply.setSectionName(studentApplyImportVO.getSectionName());
            eduStudentApply.setGradeName(studentApplyImportVO.getGradeName());
            eduStudentApply.setClassName(studentApplyImportVO.getClassName());

            eduStudentApply.setSchoolName(dept.getDeptName());
            eduStudentApply.setSchoolId(dept.getDeptId());

            if (CollUtil.isEmpty(currentStudentList)) {
                StudentApplyImportErrorVO errorVO = new StudentApplyImportErrorVO();
                errorVO.setErrorMsg(baseMag + "学生学号有误");
                errorVOList.add(errorVO);
                progressVO.setCurrentNum(index - 1);
                continue;
            }
            eduStudentApply.setStudentNumber(currentStudentList.get(0).getStuNumber());
            if (!ObjectUtil.equal(studentApplyImportVO.getStudentName(), currentStudentList.get(0).getStuName())) {
                StudentApplyImportErrorVO errorVO = new StudentApplyImportErrorVO();
                errorVO.setErrorMsg(baseMag + "学生姓名与学号不匹配");
                errorVOList.add(errorVO);
                progressVO.setCurrentNum(index - 1);
                continue;
            }
            eduStudentApply.setStudentName(currentStudentList.get(0).getStuName());

            EduUserDept campus = eduUserDeptService.getById(currentStudentList.get(0).getCampusId());
            if (campus.getDeptName().equals(studentApplyImportVO.getCampusName())) {
                eduStudentApply.setCampusId(currentStudentList.get(0).getCampusId());
            } else {
                StudentApplyImportErrorVO errorVO = new StudentApplyImportErrorVO();
                errorVO.setErrorMsg(baseMag + "学区名称与学区名称不匹配");
                errorVOList.add(errorVO);
                progressVO.setCurrentNum(index - 1);
                continue;
            }

            EduUserDept section = eduUserDeptService.getById(currentStudentList.get(0).getSectionId());
            if (section.getDeptName().equals(studentApplyImportVO.getSectionName())) {
                eduStudentApply.setSectionId(currentStudentList.get(0).getSectionId());
            } else {
                StudentApplyImportErrorVO errorVO = new StudentApplyImportErrorVO();
                errorVO.setErrorMsg(baseMag + "学段名称与学段名称不匹配");
                errorVOList.add(errorVO);
                progressVO.setCurrentNum(index - 1);
                continue;
            }

            EduUserDept grade = eduUserDeptService.getById(currentStudentList.get(0).getGradeId());
            if (grade.getDeptName().equals(studentApplyImportVO.getGradeName())) {
                eduStudentApply.setGradeId(currentStudentList.get(0).getGradeId());
            } else {
                StudentApplyImportErrorVO errorVO = new StudentApplyImportErrorVO();
                errorVO.setErrorMsg(baseMag + "学生年级名称与年级名称不匹配");
                errorVOList.add(errorVO);
                progressVO.setCurrentNum(index - 1);
                continue;
            }

            EduUserDept clazz = eduUserDeptService.getById(currentStudentList.get(0).getClassId());
            if (clazz.getDeptName().equals(studentApplyImportVO.getClassName())) {
                eduStudentApply.setClassId(currentStudentList.get(0).getClassId());
            } else {
                StudentApplyImportErrorVO errorVO = new StudentApplyImportErrorVO();
                errorVO.setErrorMsg(baseMag + "学生班级名称与班级名称不匹配");
                errorVOList.add(errorVO);
                progressVO.setCurrentNum(index - 1);
                continue;
            }

            log.info("行数据：{}", studentApplyImportVO);
            Dict dict = commonService.getDictByTypeAndValueOrLabel("apply_type", null, studentApplyImportVO.getApplyName());
            log.info("获取字典信息：{}", dict);
            if (ObjectUtil.isNull(dict)) {
                StudentApplyImportErrorVO errorVO = new StudentApplyImportErrorVO();
                errorVO.setErrorMsg(baseMag + "无此应用");
                errorVOList.add(errorVO);
                progressVO.setCurrentNum(index - 1);
                continue;
            } else {
                eduStudentApply.setApplyCode(dict.getValue());
                eduStudentApply.setApplyName(studentApplyImportVO.getApplyName());
            }
            eduStudentApply.setStudentId(currentStudentList.get(0).getId());
            String startTime = studentApplyImportVO.getStartTime();
            if (startTime.contains("/")) {
                startTime = startTime.replaceAll("/", "-");
            }

            String endTime = studentApplyImportVO.getEndTime();
            if (endTime.contains("/")) {
                endTime = endTime.replaceAll("/", "-");
            }

            eduStudentApply
                .setStartTime(LocalDateTimeUtil
                    .parse(startTime + " 00:00:00", "yyyy-MM-dd HH:mm:ss"));
            eduStudentApply
                .setEndTime(LocalDateTimeUtil
                    .parse(endTime + " 00:00:00", "yyyy-MM-dd HH:mm:ss"));

            saveData.add(eduStudentApply);

            progressVO.setCurrentNum(index - 1);
            redisService.hset(CachePrefixConstant.IMPORT_STUDENT_APPLY_PROGRESS, redisKey, progressVO);
        }
        if (CollUtil.isNotEmpty(saveData)) {
            super.saveBatch(saveData);
        }

        productErrorExcel(errorVOList, progressVO);
    }

    @Override
    public StudentApplyImportProgressVO getImportStudentApplyInfoProgress(String redisKey) {
        return (StudentApplyImportProgressVO) redisService
            .hget(CachePrefixConstant.IMPORT_STUDENT_APPLY_PROGRESS, redisKey);
    }


    public void productErrorExcel(List<StudentApplyImportErrorVO> errorVOList, StudentApplyImportProgressVO progressVO) {
        // 错误信息文件名称
        if (CollUtil.isNotEmpty(errorVOList)) {
            String fileName = FileUtil.getLocalUploadAddress() + UUID.randomUUID().toString() + ".xlsx";
            EasyExcel.write(fileName, StudentApplyImportErrorVO.class)
                .sheet("错误信息")
                .doWrite(errorVOList);
            // 上传到媒资
            String url = FileUtil.uploadFileToMediaServer(uploadUrl, new File(fileName));
            progressVO.setErrorPageUrl(url);
        }
        progressVO.setFinish(1);
        redisService.hset(CachePrefixConstant.IMPORT_STUDENT_APPLY_PROGRESS, progressVO.getRedisKey(), progressVO);
    }

    /**
     * 检测插入数据是否为空
     *
     * @return
     */
    public StudentApplyImportErrorVO checkImportDataIsNull(Integer index, StudentApplyImportVO studentApplyImportVO) {
        StudentApplyImportErrorVO studentApplyImportErrorVO = null;
        String baseMag = "第" + index + "行，";
        if (ObjectUtil.isNull(studentApplyImportVO.getSchoolName())) {
            studentApplyImportErrorVO = new StudentApplyImportErrorVO();
            studentApplyImportErrorVO.setErrorMsg(baseMag + "学校名称为空");
        }
        if (ObjectUtil.isNull(studentApplyImportVO.getStudentName())) {
            studentApplyImportErrorVO = new StudentApplyImportErrorVO();
            studentApplyImportErrorVO.setErrorMsg(baseMag + "学生姓名为空");
        }
        if (ObjectUtil.isNull(studentApplyImportVO.getStudentNumber())) {
            studentApplyImportErrorVO = new StudentApplyImportErrorVO();
            studentApplyImportErrorVO.setErrorMsg(baseMag + "学生学号为空");
        }
        if (ObjectUtil.isNull(studentApplyImportVO.getApplyName())) {
            studentApplyImportErrorVO = new StudentApplyImportErrorVO();
            studentApplyImportErrorVO.setErrorMsg(baseMag + "开通应用为空");
        }
        if (ObjectUtil.isNull(studentApplyImportVO.getStartTime())) {
            studentApplyImportErrorVO = new StudentApplyImportErrorVO();
            studentApplyImportErrorVO.setErrorMsg(baseMag + "有效开始时间为空");
        }
        if (ObjectUtil.isNull(studentApplyImportVO.getStartTime())) {
            studentApplyImportErrorVO = new StudentApplyImportErrorVO();
            studentApplyImportErrorVO.setErrorMsg(baseMag + "有效结束时间为空");
        }
        return studentApplyImportErrorVO;
    }
}
