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

import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.enums.EnabledMark;
import com.xjrsoft.common.enums.RoleEnum;
import com.xjrsoft.common.exception.MyException;
import com.xjrsoft.common.utils.RedisUtil;
import com.xjrsoft.config.CommonPropertiesConfig;
import com.xjrsoft.module.base.dto.WhitelistManagementPageDto;
import com.xjrsoft.module.base.entity.BaseClass;
import com.xjrsoft.module.base.entity.BaseUserStudent;
import com.xjrsoft.module.base.entity.TreeNode;
import com.xjrsoft.module.base.entity.WhiteBaseClass;
import com.xjrsoft.module.base.entity.WhiteBaseGrade;
import com.xjrsoft.module.base.entity.WhitelistManagement;
import com.xjrsoft.module.base.mapper.WhitelistManagementMapper;
import com.xjrsoft.module.base.service.IBaseClassService;
import com.xjrsoft.module.base.service.IBaseUserStudentService;
import com.xjrsoft.module.base.service.IWhitelistManagementService;
import com.xjrsoft.module.base.vo.WhitelistManagementPageVo;
import com.xjrsoft.module.organization.entity.User;
import com.xjrsoft.module.organization.entity.UserRoleRelation;
import com.xjrsoft.module.organization.service.IUserRoleRelationService;
import com.xjrsoft.module.organization.service.IUserService;
import com.xjrsoft.module.student.entity.BaseStudent;
import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
import com.xjrsoft.module.student.service.IBaseStudentSchoolRollService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
* @title: 白名单管理
* @Author brealinxx
* @Date: 2024-06-24
* @Version 1.0
*/
@Slf4j
@Service
@AllArgsConstructor
public class WhitelistManagementServiceImpl extends MPJBaseServiceImpl<WhitelistManagementMapper, WhitelistManagement> implements IWhitelistManagementService {
    private final WhitelistManagementMapper managementMapper;

    private RedisUtil redisUtil;

    private final IUserService userService;
    private final IBaseClassService classService;
    private final IBaseStudentSchoolRollService rollService;
    private final CommonPropertiesConfig propertiesConfig;
    private final IBaseUserStudentService userStudentService;
    private final IUserRoleRelationService roleRelationService;
    @Override
    public Page<WhitelistManagementPageVo> getPage(Page<Object> objectPage, WhitelistManagementPageDto dto) {
        return managementMapper.getPage(objectPage, dto);
    }

    @Override
    public String GetName(String name) {
        return managementMapper.getName(name);
    }

    @Override
    public String GetCredentialNumber(String credentialNumber) {
        return managementMapper.getCredentialNumber(credentialNumber);
    }

    @Override
    public String GetPhone(String phone) {
        return managementMapper.getPhone(phone);
    }

    @Override
    public Long getUserId(String credentialNumber) {
        return managementMapper.getUserId(credentialNumber);
    }

    @Override
    public boolean checkExist(String credentialNumber) {
        return managementMapper.checkExits(credentialNumber);
    }

    @Override
    public List<TreeNode> getTreeStructure() {
        List<WhiteBaseGrade> grades = managementMapper.getAllGrades();
        List<TreeNode> treeNodes = new ArrayList<>();

        for (WhiteBaseGrade grade : grades) {
            TreeNode gradeNode = new TreeNode();
            gradeNode.setId(grade.getId());
            gradeNode.setName(grade.getName());

            List<WhiteBaseClass> classes = managementMapper.getClassesByGradeId(grade.getId());
            List<TreeNode> classNodes = new ArrayList<>();

            for (WhiteBaseClass clazz : classes) {
                TreeNode classNode = new TreeNode();
                classNode.setId(clazz.getId());
                classNode.setName(clazz.getName());
                classNodes.add(classNode);
            }

            gradeNode.setChildren(classNodes);
            treeNodes.add(gradeNode);
        }

        return treeNodes;
    }

    /**
     * 所有学生电信开卡用户缓存
     */
    @Async
    public void loadCaches() {
        log.info("XJRSOFT: 加载所有学生电信开卡用户缓存开始");
        List<WhitelistManagement> list = managementMapper.getCachesList();

        Map<Long, Long> map = list.stream().collect(Collectors.toMap(WhitelistManagement::getUserId, WhitelistManagement::getUserId));
        redisUtil.set(GlobalConstant.WHITE_MANAGEMENT_CACHE_KEY, map);
        log.info("XJRSOFT: 加载所有学生电信开卡用户缓存结束");
    }

    @Override
    public List<Map<Integer, Object>> importData(List<Map<Integer, Object>> savedDataList) {
        List<Map<Integer, Object>> errorList = new ArrayList<>();

        List<WhitelistManagement> whitelistManagements = new ArrayList<>();
        List<String> errorLogs = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        for (Map<Integer, Object> vo : savedDataList) {
            if(vo.get(0) == null || vo.get(1) == null || vo.get(2) == null){
                errorList.add(vo);
                continue;
            }
            if (this.checkExist(vo.get(1).toString())) {
                continue;
            }

            String name = vo.get(0).toString();
            String credentialNumber = vo.get(1).toString();
            Long userId = this.getUserId(credentialNumber);
            String phone = vo.get(2).toString();


            if (!name.isEmpty() && !credentialNumber.isEmpty() && !phone.isEmpty()) {
                WhitelistManagement whitelistManagement = new WhitelistManagement();
                whitelistManagement.setCreateDate(new Date());
                whitelistManagement.setDeleteMark(0);
                whitelistManagement.setEnabledMark(0);
                whitelistManagement.setUserId(userId);
                whitelistManagement.setName(name);
                whitelistManagement.setCredentialNumber(credentialNumber);
                whitelistManagement.setPhone(phone);
                whitelistManagements.add(whitelistManagement);
                if(vo.get(3) != null && "".equals(vo.get(3).toString())){
                    LocalDate date = LocalDate.parse(vo.get(3).toString(), formatter);
                    whitelistManagement.setEndTime(date);
                    whitelistManagement.setIsTemporary(1);
                }
            }
        }

        Boolean result = this.saveBatch(whitelistManagements);
        if(result){
            CompletableFuture.runAsync(() -> {
                this.loadCaches();
            });
        }
        if (!errorLogs.isEmpty()) {
            String detailedMessage = String.format("[导入完成但存在问题（检查输入的是否正确且存在，输入错误可能返回 null）] ", String.join("; ", errorLogs));
            throw new MyException(detailedMessage);
        }

        return errorList;
    }

    @Override
    public List<Map<Integer, Object>> activateImport(List<Map<Integer, Object>> savedDataList) {
        List<Map<Integer, Object>> errorList = new ArrayList<>();

        List<User> studentList = userService.selectJoinList(User.class,
                new MPJLambdaWrapper<User>()
                        .innerJoin(BaseStudent.class, BaseStudent::getUserId, User::getId)
        );
        Map<String, User> studentMap = new HashMap<>();
        for (User user : studentList) {
            String key = user.getName() + user.getCredentialNumber();
            studentMap.put(key, user);
        }

        List<BaseClass> classList = classService.list(new QueryWrapper<BaseClass>());
        Map<Long, Long> classTeacherMap = new HashMap<>();
        for (BaseClass baseClass : classList) {
            classTeacherMap.put(baseClass.getId(), baseClass.getTeacherId());
        }

        List<BaseStudentSchoolRoll> schoolRollList = rollService.list(new QueryWrapper<BaseStudentSchoolRoll>());
        Map<Long, Long> studentClassMap = new HashMap<>();
        for (BaseStudentSchoolRoll el : schoolRollList) {
            studentClassMap.put(el.getUserId(), el.getClassId());
        }

        List<User> parents = userService.list(
                new QueryWrapper<User>().lambda()
                        .notIn(User::getId, "SELECT user_id FROM base_student")
        );
        Map<String, User> parentsMap = new HashMap<>();
        for (User parent : parents) {
            parentsMap.put(parent.getMobile(), parent);
        }

        Set<Long> whitelistUsers = this.baseMapper.selectList(new QueryWrapper<>()).stream().map(WhitelistManagement::getUserId).collect(Collectors.toSet());
        // 1、先把文件中的所有家长信息去重并提取出来
        Map<String, String> phoneNameMap = new HashMap<>();
        List<Map<Integer, Object>> dataList = new ArrayList<>();
        for (Map<Integer, Object> vo : savedDataList) {
            List<String> errorLogs = new ArrayList<>();

            if(vo.get(0) == null || "".equals(vo.get(0).toString())){
                errorLogs.add("学生姓名为空");
            }
            if(vo.get(1) == null || "".equals(vo.get(1).toString())){
                errorLogs.add("学生身份证为空");
            }
            if(vo.get(2) == null || "".equals(vo.get(2).toString())){
                errorLogs.add("智慧校园卡号为空");
            }
            if(vo.get(3) == null || "".equals(vo.get(3).toString())){
                errorLogs.add("家长姓名为空");
            }
            if(vo.get(4) == null || "".equals(vo.get(4).toString())){
                errorLogs.add("家长手机号为空");
            }
            String studentKey = vo.get(0).toString() + vo.get(1).toString();
            if(!studentMap.containsKey(studentKey)){
                errorLogs.add("未能查询到该学生");
            }
            if(vo.get(3) != null && vo.get(4) != null
                    && phoneNameMap.get(vo.get(4).toString()) != null
                    && !vo.get(3).toString().equals(phoneNameMap.get(vo.get(4).toString()))){
                errorLogs.add("手机号已被其他家长使用，请检查是否正确");
            }

            if(!errorLogs.isEmpty()){
                vo.put(5, errorLogs.toString().replace("[", "").replace("]", ""));
                errorList.add(vo);
                continue;
            }
            phoneNameMap.put(vo.get(4).toString(), vo.get(3).toString());
            dataList.add(vo);
        }
        LocalDateTime now = LocalDateTime.now();
        Date createDate = new Date();
        Set<String> parentKeySet = dataList.stream().map(x -> x.get(3).toString() + "<@>" + x.get(4).toString()).collect(Collectors.toSet());

        List<User> parentInsList = new ArrayList<>();
        List<User> parentUpdList = new ArrayList<>();
        List<UserRoleRelation> roleRelationList = new ArrayList<>();
        Map<String, Long> parentIdMap = new HashMap<>();
        for (String parentKey : parentKeySet) {
            String[] split = parentKey.split("<@>");
            long parentId = IdUtil.getSnowflakeNextId();
            if(parentsMap.get(split[1]) != null){
                User parent = parentsMap.get(split[1]);
                parentId = parent.getId();
                parent.setName(split[0]);
                parent.setModifyDate(now);
                parentUpdList.add(parent);
            }else{
                User parent = new User();
                parent.setId(parentId);
                parent.setPassword(BCrypt.hashpw(split[1], BCrypt.gensalt()));
                parent.setCreateDate(now);
                parent.setMobile(split[1]);
                parent.setName(split[0]);
                parent.setUserName(split[1]);
                parent.setIsChangePassword(1);
                parentInsList.add(parent);

                UserRoleRelation roleRelation = new UserRoleRelation();
                roleRelation.setRoleId(RoleEnum.PARENT.getCode());
                roleRelation.setUserId(parentId);
                roleRelationList.add(roleRelation);
            }
            parentIdMap.put(parentKey, parentId);
        }
        
        List<User> updateList = new ArrayList<>();
        List<BaseUserStudent> userStudentList = new ArrayList<>();
        List<WhitelistManagement> whitelist = new ArrayList();

        for (Map<Integer, Object> vo : dataList) {
            String studentKey = vo.get(0).toString() + vo.get(1).toString();

            User user = studentMap.get(studentKey);
            user.setMobile(vo.get(2).toString());
            user.setEnabledMark(EnabledMark.ENABLED.getCode());
            updateList.add(user);
            Long classId = studentClassMap.get(user.getId());
            Long teacherId = classTeacherMap.get(classId);

            BaseUserStudent userStudent = new BaseUserStudent();
            userStudent.setStatus(1);
            userStudent.setStudentId(user.getId());
            userStudent.setStudentIdentity(user.getCredentialNumber());
            userStudent.setStudentNane(user.getName());
            userStudent.setCreateDate(new Date());
            userStudent.setClassId(classId);
            userStudent.setTeacherId(teacherId);
            userStudent.setUserId(parentIdMap.get(vo.get(3).toString() + "<@>" + vo.get(4).toString()));
            userStudent.setUserPhone(vo.get(4).toString());
            userStudentList.add(userStudent);

            if(!whitelistUsers.contains(user.getId())){
                whitelist.add(new WhitelistManagement(){{
                    setCredentialNumber(user.getCredentialNumber());
                    setUserId(user.getId());
                    setName(user.getName());
                    setPhone(user.getMobile());
                    setCreateDate(createDate);
                }});
            }
        }

        if(!updateList.isEmpty()){
            userService.updateBatchById(updateList);
        }
        if(!userStudentList.isEmpty()){
            userStudentService.saveBatch(userStudentList);
        }
        if(!parentInsList.isEmpty()){
            userService.saveBatch(parentInsList);
        }
        if(!parentUpdList.isEmpty()){
            userService.updateBatchById(parentUpdList);
        }
        if(!roleRelationList.isEmpty()){
            roleRelationService.saveBatch(roleRelationList);
        }
        if(!whitelist.isEmpty()){
            this.saveBatch(whitelist);
        }

        CompletableFuture.runAsync(() -> {
            List<User> list = userService.list();
            redisUtil.set(GlobalConstant.USER_CACHE_KEY, list);

            List<UserRoleRelation> userRoleRelationList = roleRelationService.list(Wrappers.lambdaQuery(UserRoleRelation.class));
            redisUtil.set(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, userRoleRelationList);

            this.loadCaches();
        });

        return errorList;
    }

    @Override
    public List<WhitelistManagement> getCachesList() {
        return this.baseMapper.getCachesList();
    }
}