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

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yida.data.common.core.common.ResultBean;
import com.yida.data.common.core.entity.apply.enums.DelFlagType;
import com.yida.data.common.core.entity.constant.AppConstant;
import com.yida.data.common.core.entity.message.EduMessageStrategy;
import com.yida.data.common.core.entity.notice.app.AppNotice;
import com.yida.data.common.core.entity.notice.app.inside.PushMessage;
import com.yida.data.common.core.entity.school.EduSchoolParentInformation;
import com.yida.data.common.core.entity.school.EduSchoolStudentInformation;
import com.yida.data.common.core.entity.school.EduYidaAppAccount;
import com.yida.data.common.core.entity.system.Dept;
import com.yida.data.common.core.entity.system.EduApp;
import com.yida.data.common.core.entity.system.EduYidaApp;
import com.yida.data.common.core.entity.user.*;
import com.yida.data.common.core.enums.DataStatusEnum;
import com.yida.data.common.core.enums.ReportStatusEnum;
import com.yida.data.common.core.utils.AppUtil;
import com.yida.data.common.core.utils.DaHuaUtil;
import com.yida.data.common.core.utils.WxUtil;
import com.yida.data.common.service.CommonService;
import com.yida.data.user.dto.SaveParentInformationDTO;
import com.yida.data.user.mapper.EduParentMapper;
import com.yida.data.user.mapper.EduSchoolParentInformationMapper;
import com.yida.data.user.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 学校智慧迎新-家长填报信息service层
 *
 * @author ZYJ
 * @date 2021/8/20
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class EduSchoolParentInformationServiceImpl extends ServiceImpl<EduSchoolParentInformationMapper, EduSchoolParentInformation>
        implements EduSchoolParentInformationService {

    private final EduParentService eduParentService;
    private final EduStudentService eduStudentService;
    private final EduUserDeptService eduUserDeptService;
    private final EduParentTypeService eduParentTypeService;
    private final EduParentStudentService eduParentStudentService;
    private final EduMessageStrategyService eduMessageStrategyService;
    private final EduSchoolStudentInformationService eduSchoolStudentInformationService;
    private final EduUserFaceService eduUserFaceService;

    private final EduParentMapper eduParentMapper;

    private final WxUtil wxUtil;
    private final CommonService commonService;

    private static final ExecutorService UPDATE_PARENT_THREAD_POOL = new ThreadPoolExecutor(5, 10, 1,
            TimeUnit.MINUTES, new LinkedBlockingQueue<>(), ThreadUtil.newNamedThreadFactory("welcome-pool-%d", false));

    /**
     * 保存家长提交信息
     *
     * @param saveParentInformationDTO 家长提交信息
     * @return com.yida.data.common.core.common.ResultBean<java.lang.String>
     * @author ZYJ
     * @date 2021/8/19 20:59
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultBean<String> saveParentInformation(SaveParentInformationDTO saveParentInformationDTO) {
        // 当前时间
        LocalDateTime now = LocalDateTime.now();
        // 循环保存智慧迎新家长填报数据
        for (SaveParentInformationDTO.ParentInformationDTO parentInformationDTO : saveParentInformationDTO.getParentInfoList()) {
            // 循环学生信息
            for (Long studentId : saveParentInformationDTO.getStudentIdList()) {
                // 修改学生报到状态
                this.eduSchoolStudentInformationService.saveOrUpdate(EduSchoolStudentInformation.builder()
                        .id(studentId)
                        .reportStatus(ReportStatusEnum.REPORTED_STATUS.getStatus())
                        .build());
                // 保存填报显示数据
                this.save(EduSchoolParentInformation.builder()
                        .createDate(now)
                        .studentInformationId(studentId)
                        .checkDate(now)
                        .reportParentsInfo(parentInformationDTO.getParentRole() + "-" + parentInformationDTO.getParentTelephone())
                        .build());
            }
        }
        // 判断学校类型
        Dept school = commonService.getDept(saveParentInformationDTO.getSchoolId());
        boolean containWx = school.getSchoolType().contains(Dept.TYPE_QYWX);
        boolean containYiDa = school.getSchoolType().contains(Dept.TYPE_YIDA_APP);
        boolean containDaHua = school.getSchoolType().contains(Dept.TYPE_DAHUA);
        // 部门缓存
        Map<Long, EduUserDept> userDeptMap = new HashMap<>();

        // 上报的学生数据集合
        List<EduStudent> reportStudent = new ArrayList<>();
        // 保存学生数据到本地
        for (Long studentId : saveParentInformationDTO.getStudentIdList()) {
            // 查询验证的学生数据
            EduSchoolStudentInformation eduSchoolStudentInformation = this.eduSchoolStudentInformationService.getById(studentId);
            // 判断学生是否存在数据
            EduStudent eduStudent = this.eduStudentService.getOne(Wrappers.<EduStudent>lambdaQuery()
                    .eq(EduStudent::getSchoolId, eduSchoolStudentInformation.getSchoolId())
                    .eq(EduStudent::getStuNumber, eduSchoolStudentInformation.getStudentNumber()));
            // 不存在, 保存新的学生数据
            if (!Optional.ofNullable(eduStudent).isPresent()) {
                eduStudent = new EduStudent();
                BeanUtils.copyProperties(eduSchoolStudentInformation, eduStudent);
                // 设置无法拷贝的属性
                eduStudent.setCreateDate(now);
                eduStudent.setStartDate(LocalDate.now());
                eduStudent.setStuName(eduSchoolStudentInformation.getStudentName());
                eduStudent.setIdNumber(eduSchoolStudentInformation.getStudentIdCard());
                // 设置学号和企业微信学生id
                String stuNumber = eduSchoolStudentInformation.getStudentNumber();
                eduStudent.setStuNumber(stuNumber);
                eduStudent.setWxId(stuNumber);
                // 判断是否包含大华
                if (containDaHua) {
                    setDaHuaInfo(eduStudent, userDeptMap, school);
                }
                // 保存数据到本地学生库
                eduStudentService.save(eduStudent);
                eduStudent.setIsCreate(DataStatusEnum.CREATE_STATUS.getStatus());
            } else {
                eduStudent.setIsCreate(DataStatusEnum.UPDATE_STATUS.getStatus());
            }
            // 查询学生班级对应的企业微信id
            eduStudent.setClassWxId(this.commonService.getUserDept(eduSchoolStudentInformation.getClassId()).getWxId());
            reportStudent.add(eduStudent);
        }
        // 上报的家长数据集合
        List<EduParent> reportParent = new ArrayList<>();
        // 保存家长数据到本地
        for (SaveParentInformationDTO.ParentInformationDTO parentInformationDTO : saveParentInformationDTO.getParentInfoList()) {
            // 判断家长是否存在数据
            EduParent eduParent = this.eduParentService.
                    getOne(Wrappers.lambdaQuery(new EduParent())
                            .eq(EduParent::getMobile, parentInformationDTO.getParentTelephone())
                            .eq(EduParent::getSchoolId, saveParentInformationDTO.getSchoolId()));
            // 不存在, 保存新的家长数据
            if (!Optional.ofNullable(eduParent).isPresent()) {
                eduParent = new EduParent();
                // 设置需要保存的数据
                eduParent.setMobile(parentInformationDTO.getParentTelephone());
                eduParent.setSchoolId(saveParentInformationDTO.getSchoolId());
                eduParent.setParentType(parentInformationDTO.getParentRole());
                eduParent.setWxId(StrUtil.uuid().replace("-", ""));
                // 保存本地家长信息
                eduParent = this.eduParentService.saveLocalParent(eduParent);
                eduParent.setIsCreate(DataStatusEnum.CREATE_STATUS.getStatus());
            } else {
                eduParent.setIsCreate(DataStatusEnum.UPDATE_STATUS.getStatus());
                // 保存家长类型数据
                EduParentType eduParentType = eduParentTypeService.getParentType(parentInformationDTO.getParentRole());
                eduParent.setParentType(eduParentType.getName());
                eduParent.setParentTypeId(eduParentType.getId());
            }
            // 循环添加家长和学生关系
            for (EduStudent eduStudent : reportStudent) {
                // 查询学生和家长是否存在关系数据
                EduParentStudent eduParentStudent = eduParentStudentService.getOne(Wrappers.lambdaQuery(new EduParentStudent())
                        .eq(EduParentStudent::getParentId, eduParent.getId())
                        .eq(EduParentStudent::getStudentId, eduStudent.getId()));
                if (!Optional.ofNullable(eduParentStudent).isPresent()) {
                    eduParentStudent = new EduParentStudent();
                    eduParentStudent.setParentId(eduParent.getId());
                    eduParentStudent.setStudentId(eduStudent.getId());
                    eduParentStudent.setParentTypeId(eduParent.getParentTypeId());
                    // 保存本地家长和学生类型关系数据
                    eduParentStudentService.save(eduParentStudent);
                }
            }
            eduParent.setChildren(new ArrayList<>());
            // 查询数据库中已存在的家长和学生关系数据
            List<EduParentStudent> eduParentStudentList = eduParentStudentService.listParentStudent(eduParent.getId());
            // 添加企业微信家长学生关系数据
            for (EduParentStudent parentStudent : eduParentStudentList) {
                Map<String, Object> student = new HashMap<>(16);
                student.put("student_userid", parentStudent.getStudentWxId());
                student.put("relation", parentStudent.getParentTypeName());
                eduParent.getChildren().add(student);
            }
            reportParent.add(eduParent);
        }
        // 判断是否企业微信
        if (containWx) {
            setWxUser(reportStudent, reportParent, saveParentInformationDTO);
        }
        // 学校绑定了易达app
        if (containYiDa) {
            EduYidaApp yiDaApp = commonService.getYidaApp(school.getDeptId());
            EduYidaAppAccount yiDaAppAccount = commonService.getYidaAppAccount(school.getDeptId(), 0);

            for (EduParent parent : reportParent) {
                UPDATE_PARENT_THREAD_POOL.execute(() -> {
                    parent.setYidaAppUserId(AppUtil.userSave(parent.getMobile(), "用户" + parent.getMobile(),
                            yiDaApp));
                    AppUtil.subscribeFollow(yiDaAppAccount.getYidaAppAccountId(),
                            parent.getYidaAppUserId(), yiDaApp);
                    if (DataStatusEnum.CREATE_STATUS.getStatus().equals(parent.getIsCreate())) {
                        for (EduStudent student : reportStudent) {
                            // 推送关注消息
                            AppNotice appNotice = new AppNotice();
                            appNotice.setUserIds(Collections.singletonList(parent.getYidaAppUserId()));
                            PushMessage message = new PushMessage();
                            message.setMsgType(PushMessage.TEXT);
                            EduMessageStrategy data = eduMessageStrategyService
                                    .getOne(Wrappers.lambdaQuery(new EduMessageStrategy())
                                            .eq(EduMessageStrategy::getSchoolId, saveParentInformationDTO.getSchoolId())
                                            .eq(EduMessageStrategy::getType, 1)
                                            .eq(EduMessageStrategy::getSubType, 1)
                                            .eq(EduMessageStrategy::getDelFlag, DelFlagType.NORMAL_TYPE.getValue()));
                            message.setContent(data != null ? data.getContent() :
                                    String.format("亲爱的%s，欢迎加入%s智慧校园！您可以在这里接收到学生在学校的动态消息，了解学生在学校的情况，更好地陪伴孩子成长！"
                                            , student.getStuName() + parent.getParentType(), school.getDeptName()));
                            message.setAccountId(yiDaAppAccount.getYidaAppAccountId());
                            appNotice.setMsgList(Collections.singletonList(message));
                            appNotice.setPushMessage(new PushMessage(school.getDeptName() + "智慧校园",
                                    yiDaAppAccount.getYidaAppAccountId()));
                            AppUtil.sendMsg(appNotice, yiDaApp);
                        }
                    }
                    eduParentMapper.updateById(parent);
                });
            }
        }

        return ResultBean.buildSuccess();
    }

    /**
     * 保存企业微信数据
     *
     * @param reportStudent            上报的学生信息
     * @param reportParent             上报的家长信息
     * @param saveParentInformationDTO 保存家长信息请求类
     * @author ZYJ
     * @date 2022/7/18 17:22
     */
    private void setWxUser(List<EduStudent> reportStudent, List<EduParent> reportParent,
                           SaveParentInformationDTO saveParentInformationDTO) {
        // 调用企业微信批量创建学生接口, 若失败则抛出异常
        List<EduStudent> createStudentList = reportStudent.stream()
                .filter(eduStudent -> eduStudent.getIsCreate().equals(DataStatusEnum.CREATE_STATUS.getStatus()))
                .collect(Collectors.toList());
        log.info("调用企业微信创建学生数据: {}", JSON.toJSONString(createStudentList));
        if (!CollectionUtils.isEmpty(createStudentList)) {
            // 微信app与token
            EduApp app = commonService.getAppByCodeAndSchool(AppConstant.CONTACT_SCHOOL, null, saveParentInformationDTO.getSchoolId());
            String token = wxUtil.getAccessToken(app.getWxCorpId(), app.getWxSecret());
            wxUtil.createStudent(token, createStudentList);
        }
        // 调用企业微信批量创建家长接口, 若失败则抛出异常
        List<EduParent> createParentList = reportParent.stream()
                .filter(eduParent -> DataStatusEnum.CREATE_STATUS.getStatus().equals(eduParent.getIsCreate()))
                .collect(Collectors.toList());
        log.info("调用企业微信创建家长数据: {}", JSON.toJSONString(createStudentList));
        if (!CollectionUtils.isEmpty(createParentList)) {
            // 微信app与token
            EduApp app = commonService.getAppByCodeAndSchool(AppConstant.CONTACT_SCHOOL, null, saveParentInformationDTO.getSchoolId());
            String token = wxUtil.getAccessToken(app.getWxCorpId(), app.getWxSecret());
            wxUtil.createParent(token, createParentList);
        }
        // 调用企业微信批量更新家长接口, 若失败则抛出异常
        List<EduParent> updateParentList = reportParent.stream()
                .filter(eduParent -> DataStatusEnum.UPDATE_STATUS.getStatus().equals(eduParent.getIsCreate()))
                .collect(Collectors.toList());
        log.info("调用企业微信更新家长数据: {}", JSON.toJSONString(updateParentList));
        if (!CollectionUtils.isEmpty(updateParentList)) {
            // 微信app与token
            EduApp app = commonService.getAppByCodeAndSchool(AppConstant.CONTACT_SCHOOL, null, saveParentInformationDTO.getSchoolId());
            String token = wxUtil.getAccessToken(app.getWxCorpId(), app.getWxSecret());
            wxUtil.updateParent(token, updateParentList);
        }
    }

    /**
     * 设置大华信息
     *
     * @param eduStudent  学生信息
     * @param userDeptMap 家校部门缓存map
     * @param school      学校信息
     * @author ZYJ
     * @date 2022/7/18 16:54
     */
    private void setDaHuaInfo(EduStudent eduStudent, Map<Long, EduUserDept> userDeptMap, Dept school) {
        // 学区
        EduUserDept campus;
        if (userDeptMap.containsKey(eduStudent.getCampusId())) {
            campus = userDeptMap.get(eduStudent.getCampusId());
        } else {
            campus = eduUserDeptService.getById(eduStudent.getCampusId());
            userDeptMap.put(eduStudent.getCampusId(), campus);
        }
        // 学段
        EduUserDept section;
        if (userDeptMap.containsKey(eduStudent.getSectionId())) {
            section = userDeptMap.get(eduStudent.getSectionId());
        } else {
            section = eduUserDeptService.getById(eduStudent.getSectionId());
            userDeptMap.put(eduStudent.getSectionId(), section);
        }
        // 年级
        EduUserDept grade;
        if (userDeptMap.containsKey(eduStudent.getGradeId())) {
            grade = userDeptMap.get(eduStudent.getGradeId());
        } else {
            grade = eduUserDeptService.getById(eduStudent.getGradeId());
            userDeptMap.put(eduStudent.getGradeId(), grade);
        }
        // 班级
        EduUserDept clazz;
        if (userDeptMap.containsKey(eduStudent.getClassId())) {
            clazz = userDeptMap.get(eduStudent.getClassId());
        } else {
            clazz = eduUserDeptService.getById(eduStudent.getClassId());
            userDeptMap.put(eduStudent.getClassId(), clazz);
        }

        // 人脸信息
        EduUserFace userFace = eduUserFaceService.getOne(Wrappers.lambdaQuery(new EduUserFace())
                .eq(EduUserFace::getUserId, eduStudent.getId())
                .eq(EduUserFace::getUserType, 0));

        // 设置大华学号
        eduStudent.setDahuaCode(eduStudent.getStuNumber().length() > 20
                ? DaHuaUtil.generateCode()
                : eduStudent.getStuNumber());
        String cardNum = DaHuaUtil.generateCardNum();
        eduStudent.setDahuaId(
                DaHuaUtil.addUser(eduStudent.getStuName(), eduStudent.getDahuaCode(), 0, 1, cardNum,
                        school.getDahuaId(), campus.getDaHuaId(), section.getDaHuaId(), grade.getDaHuaId(),
                        clazz.getDaHuaId(), Objects.nonNull(userFace) ? userFace.getPicPath() : ""));
    }

    /***
     * @Author jianMingWang
     * @Description //获取已提交信息学生
     * @Date 9:18 2021/8/23
     * @Param [schoolId]
     * @return java.lang.Integer
     **/
    @Override
    public Integer getCheckNum(Long schoolId) {
        return baseMapper.getCheckNum(schoolId);
    }
}
