package com.rongwei.sfcommon.sys.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rongwe.scentity.domian.AspSafeAttachmentsDo;
import com.rongwe.scentity.domian.CheckItemsDo;
import com.rongwe.scentity.vo.CheckAreaVo;
import com.rongwe.scentity.vo.ImportAspSafeAttachmentsVo;
import com.rongwe.scentity.vo.SysNoticeVo;
import com.rongwe.scentity.vo.UserMailOrgVo;
import com.rongwei.rwadmincommon.system.domain.SysDictDo;
import com.rongwei.rwadmincommon.system.domain.SysOrganizationDo;
import com.rongwei.rwadmincommon.system.domain.SysUserDo;
import com.rongwei.rwadmincommon.system.service.SysConfigFeignService;
import com.rongwei.rwadmincommon.system.vo.SysUserVo;
import com.rongwei.rwcommon.base.R;
import com.rongwei.rwcommon.base.exception.CustomException;
import com.rongwei.rwcommon.utils.SecurityUtil;
import com.rongwei.rwcommon.vo.MailDo;
import com.rongwei.rwcommonentity.commonservers.domain.SysFileItemDo;
import com.rongwei.safecommon.utils.CXCommonUtils;
import com.rongwei.sfcommon.sys.dao.AspSafeAttachmentsDao;
import com.rongwei.sfcommon.sys.dao.AspSpecialEquipmentCertificateDao;
import com.rongwei.sfcommon.sys.dao.SaveCheckCommonDao;
import com.rongwei.sfcommon.sys.service.AspSafeAttachmentsService;
import com.rongwei.sfcommon.utils.ClassExcelVerifyHandler;
import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

import static com.rongwei.safecommon.utils.SaveConstans.*;
import static com.rongwei.safecommon.utils.SaveConstans.NotifyContent.EQUIPMENT_CHECK_CONTENT;
import static com.rongwei.safecommon.utils.SaveConstans.NotifyContent.SAFETY_ATTACHMENT_VERIFICATION_CONTENT;
import static com.rongwei.safecommon.utils.SaveConstans.NotifyTitle.SAFETY_ATTACHMENT_VERIFICATION_TITLE;
import static com.rongwei.safecommon.utils.SaveConstans.NotifyType.SAFETY_ATTACHMENT_VERIFICATION;
import static com.rongwei.safecommon.utils.SaveConstans.NotifyType.SPECIALEQUIPMENT;

/**
 *
 */
@Service
public class AspSafeAttachmentsServiceImpl extends ServiceImpl<AspSafeAttachmentsDao, AspSafeAttachmentsDo>
        implements AspSafeAttachmentsService {
    /**
     * 组织机构代码
     */
    public static final List<String> ROLE_CODE_LIST = new ArrayList<String>() {{
        add("code-safe");
        add("role031");
        add("produce");
    }};
    /**
     * 特种设备管理员
     */
    public static final String SPECIAL_EQUIPMENT_ADMINISTRATOR = "role031";
    public static final String EMPTY_ERROR_MSG = "第%s行 %s 为空";
    public static final String DATE_FORMAT_ERROR_MSG = "第%s行 %s 时间格式不正确";
    public static final List<SimpleDateFormat> DATE_FORMAT_LIST = new ArrayList<SimpleDateFormat>() {{
        add(new SimpleDateFormat("yyyy-MM-dd"));
        add(new SimpleDateFormat("yyyy/MM/dd"));
        add(new SimpleDateFormat("yyyy.MM.dd"));
        add(new SimpleDateFormat("yyyyMMdd"));
    }};

    private final Logger log = LoggerFactory.getLogger(this.getClass().getName());
    @Autowired
    private SaveCheckCommonDao saveCheckCommonDao;
    @Autowired
    private ClassExcelVerifyHandler verifyHandler;
    @Resource
    private SysConfigFeignService sysConfigFeignService;
    @Resource
    private AspSpecialEquipmentCertificateDao aspSpecialEquipmentCertificateDao;

    @Override
    public R stateUpdateScheduledTasks() {
        // 获取所有的安全附件
        List<AspSafeAttachmentsDo> safeAttachmentsDos = this.list();
        if (safeAttachmentsDos.isEmpty()) {
            return R.ok("暂无安全附件");
        }
        // 对数据按照租户ID 分组
        Map<String, List<AspSafeAttachmentsDo>> dataMap = safeAttachmentsDos.stream().collect(Collectors.groupingBy(AspSafeAttachmentsDo::getTenantid));
        List<AspSafeAttachmentsDo> saveData = new ArrayList<>();
        // 发送消息提醒的参数
        Map<AspSafeAttachmentsDo, List<String>> sendNotifyMap = new HashMap<AspSafeAttachmentsDo, List<String>>();
        // 发送邮件的集合《用户ID，List<设备信息>》
        Map<String, List<AspSafeAttachmentsDo>> sendMailMap = new HashMap<>();
        // 用户的信息集合
        Map<String, UserMailOrgVo> userMap = new HashMap<>();
        dataMap.forEach((k, v) -> {
            //获取工厂对应的 安全管理员和特种设备管理员 和生产副总
            List<UserMailOrgVo> userInfO = saveCheckCommonDao.getUserInfoByTenantIdAndRoleCode(k, ROLE_CODE_LIST);
            for (UserMailOrgVo userMailOrgVo : userInfO) {
                if (ObjectUtil.isNotEmpty(userMailOrgVo.getEmail())) {
                    sendMailMap.put(userMailOrgVo.getId(), new LinkedList<>());
                    userMap.put(userMailOrgVo.getId(), userMailOrgVo);
                }
            }
            Date manufacturedate;
            long daysBetween;
            List<String> alertUser;
            for (AspSafeAttachmentsDo data : v) {
                manufacturedate = data.getNextinspectiondate();
                LocalDate date1 = manufacturedate.toInstant()
                        .atZone(ZoneId.systemDefault())
                        .toLocalDate();
                daysBetween = ChronoUnit.DAYS.between(LocalDate.now(), date1);
                if (daysBetween <= 7) {
                    data.setReminderstate(HIGH);
                    alertUser = userInfO.stream().map(UserMailOrgVo::getId).collect(Collectors.toList());
                    sendNotifyMap.put(data, alertUser);
                    for (String userId : alertUser) {
                        if (sendMailMap.containsKey(userId)) {
                            List<String> dataIdList = sendMailMap.get(userId).stream().map(AspSafeAttachmentsDo::getId).collect(Collectors.toList());
                            if (!dataIdList.contains(data.getId())) {
                                sendMailMap.get(userId).add(data);
                            }
                        }
                    }
                } else if (daysBetween <= 90) {
                    alertUser = userInfO.stream().filter(user -> SPECIAL_EQUIPMENT_ADMINISTRATOR.equals(user.getRoleCode())).map(UserMailOrgVo::getId).collect(Collectors.toList());
                    data.setReminderstate(MIDDLE);
                    sendNotifyMap.put(data, alertUser);
                    for (String userId : alertUser) {
                        if (sendMailMap.containsKey(userId)) {
                            List<String> dataIdList = sendMailMap.get(userId).stream().map(AspSafeAttachmentsDo::getId).collect(Collectors.toList());
                            if (!dataIdList.contains(data.getId())) {
                                sendMailMap.get(userId).add(data);
                            }
                        }
                    }
                } else {

                    data.setReminderstate(LOW);
                }

                saveData.add(data);
            }
        });
        this.updateBatchById(saveData);
        sendNotify(sendNotifyMap);

        sendMail(sendMailMap, userMap);

        return R.ok();
    }


    private void sendMail(Map<String, List<AspSafeAttachmentsDo>> sendMailMap, Map<String, UserMailOrgVo> userMap) {
        if (ObjectUtil.isEmpty(sendMailMap)) {
            return;
        }
        sendMailMap.forEach((key, value) -> {
            if (ObjectUtil.isEmpty(value)) {
                return;
            }
            StringBuilder mailContent = new StringBuilder("您好！有如下安全附件即将年检到期，请及时处理！\n");
            for (int i = 0; i < value.size(); i++) {
                AspSafeAttachmentsDo attachmentsDo = value.get(i);


                //附件类型
                String attachmenttype = ObjectUtil.isNotEmpty(attachmentsDo.getAttachmenttype()) ? attachmentsDo.getAttachmenttype() : "";
                //证书/报告编号
                String number = ObjectUtil.isNotEmpty(attachmentsDo.getCertificatenumber()) ? attachmentsDo.getCertificatenumber() : "";
                //名称
                String name = ObjectUtil.isNotEmpty(attachmentsDo.getName()) ? attachmentsDo.getName() : "";
                //检验日期
                Date inspectiondate = attachmentsDo.getInspectiondate();
                String checkDate = "";
                if (ObjectUtil.isNotEmpty(inspectiondate)) {
                    checkDate = DateUtil.format(inspectiondate, "yyyy-MM-dd");
                }
                mailContent.append((i + 1) + "、附件类型：【" + attachmenttype + "】，证书/报告编号：【" + number + "】，名称：【" + name + "】，检验日期：【" + checkDate + "】\n");
            }
            mailContent.append("详见安全生产平台，如果无法点击请复制链接到浏览器中：http://192.168.100./#/page/lr/a02bf613b27c422f8e6e3b9d427b15dd");

            //发送邮件
            MailDo mailDo = new MailDo();
            mailDo.setSubject("安全附件年检提醒");
            mailDo.setReceiveEmail(new String[]{userMap.get(key).getEmail()});
            mailDo.setNeedTransReceive(false);
            mailDo.setContent(mailContent.toString());
            try {
                sysConfigFeignService.sendTextMail(mailDo);
            } catch (Exception ignored) {
            }
        });

    }


    /**
     * 发送消息提醒
     *
     * @param sendNotifyMap
     */
    public void sendNotify(Map<AspSafeAttachmentsDo, List<String>> sendNotifyMap) {
        //查询所有该类型的、未读的 消息通知
        List<SysNoticeVo> sysNoticeVo = aspSpecialEquipmentCertificateDao.selectMyNoticeByType(Arrays.asList(SAFETY_ATTACHMENT_VERIFICATION));


        sendNotifyMap.forEach((k, v) -> {

            String content = String.format(SAFETY_ATTACHMENT_VERIFICATION_CONTENT, k.getName() == null ? "" : k.getName(), k.getNumber() == null ? "" : k.getNumber(), k.getInspectiondate() == null ? "" : k.getInspectiondate(),
                    k.getNextinspectiondate() == null ? "" : k.getNextinspectiondate(), k.getResponsible() == null ? "" : k.getResponsible());
            List<String> userIdList = v.stream().distinct().collect(Collectors.toList());
            SysNoticeVo oldNoticeVo = sysNoticeVo.stream().filter(item -> item.getNotifycontent().equals(content) && item.getRoption().equals(k.getId())).distinct().findFirst().orElse(null);
            if (ObjectUtil.isNotEmpty(oldNoticeVo) && ObjectUtil.isNotEmpty(oldNoticeVo.getUserIds())) {
                userIdList.removeAll(oldNoticeVo.getUserIds());
            }

            // 发送消息提醒
            CXCommonUtils.sendNotify(SAFETY_ATTACHMENT_VERIFICATION_TITLE,
                    content, null, userIdList,
                    k.getId(), SAFETY_ATTACHMENT_VERIFICATION, false);
        });
    }

    /**
     * 导入excel
     *
     * @param queryParameter
     * @return
     */
    @SneakyThrows
    @Override
    public R importExcel(Map<String, String> queryParameter) {
        String fileId = queryParameter.getOrDefault("fileId", "");
        CXCommonUtils.parameterCheck(() -> StringUtils.isBlank(fileId), "请上传文件", "文件ID为空");
        SysFileItemDo fileItemDo = saveCheckCommonDao.getFileItemByID(fileId);
        CXCommonUtils.parameterCheck(() -> fileItemDo == null, "文件解析有误!请联系管理员", "无法根据文件ID:{},获取到文件信息", fileId);
        String realPath = fileItemDo.getFullpath();
        CXCommonUtils.parameterCheck(() -> StringUtils.isBlank(realPath), "文件解析有误!请联系管理员", "根据文件ID:{},无法获取到文件路径", fileId);
        File file = new File(realPath);
        CXCommonUtils.parameterCheck(() -> !file.exists(), "文件解析有误!请联系管理员", "根据文件地址:{},无法获取文件", realPath);
        ImportParams params = new ImportParams();
        params.setTitleRows(0);
        params.setHeadRows(1);
        params.setVerifyHandler(verifyHandler);
        List<ImportAspSafeAttachmentsVo> userList = ExcelImportUtil.importExcel(file, ImportAspSafeAttachmentsVo.class, params);
        log.info("userList:{}", userList);
        // 存放异常数据
        List<String> errorMsgList = new ArrayList<>();
        // 解析后的数据
        List<AspSafeAttachmentsDo> saveList = new ArrayList<>();
        ImportAspSafeAttachmentsVo importAspSafeAttachmentsVo;
        SysUserVo currentUser = CXCommonUtils.getCurrentUser();
        String tenantId = CXCommonUtils.getCurrentUserFactoryId(currentUser);
        //获取区域信息
        Map<String, String> checkAreaMap = saveCheckCommonDao.getCheckArea(tenantId).stream().collect(Collectors.toMap(CheckAreaVo::getName, CheckAreaVo::getId, (v1, v2) -> v1));
        // 获取组织机构信息
        Map<String, String> orgMap = saveCheckCommonDao.getOrgByTenantId(tenantId).stream().collect(Collectors.toMap(SysOrganizationDo::getFullname, SysOrganizationDo::getId, (v1, v2) -> v1));
        // 用户信息
        Map<String, String> userMap = saveCheckCommonDao.getUserInfoByTenantId(tenantId).stream().collect(Collectors.toMap(SysUserDo::getName, SysUserDo::getId, (v1, v2) -> v1));

        for (int i = 0; i < userList.size(); i++) {
            importAspSafeAttachmentsVo = userList.get(i);
            // 数据格式校验
            checkDataAccuracy(i + 1, importAspSafeAttachmentsVo, errorMsgList);

            if (StringUtils.isNotBlank(importAspSafeAttachmentsVo.getTreeName()) && !checkAreaMap.containsKey(importAspSafeAttachmentsVo.getTreeName())) {
                errorMsgList.add("第" + (i + 1) + "行树表名称不存在");
            }
            if (errorMsgList.isEmpty()) {
                saveList.add(voToDo(importAspSafeAttachmentsVo, checkAreaMap, orgMap, userMap, tenantId));
            }
        }
        if (!errorMsgList.isEmpty()) {
            log.error("excel数据异常:{}", errorMsgList);
            throw new CustomException(StringUtils.join(errorMsgList, ";"));
        }
        if (!saveList.isEmpty()) {
            this.saveBatch(saveList, 100);
        }

        return R.ok();
    }

    private void checkDataAccuracy(int index, ImportAspSafeAttachmentsVo importAspSafeAttachmentsVo, List<String> errorMsgList) {
        if (StringUtils.isBlank(importAspSafeAttachmentsVo.getTreeName())) {
            errorMsgList.add(String.format(EMPTY_ERROR_MSG, index, "左侧树表"));
        }
        if (StringUtils.isBlank(importAspSafeAttachmentsVo.getAttachmenttype())) {
            errorMsgList.add(String.format(EMPTY_ERROR_MSG, index, "附件类型"));
        }
        if (StringUtils.isBlank(importAspSafeAttachmentsVo.getName())) {
            errorMsgList.add(String.format(EMPTY_ERROR_MSG, index, "名称"));
        }
        if (StringUtils.isBlank(importAspSafeAttachmentsVo.getInspectionstr())) {
            errorMsgList.add(String.format(EMPTY_ERROR_MSG, index, "检验/更换日期"));
        }
        if (StringUtils.isBlank(importAspSafeAttachmentsVo.getNextinspectionstr())) {
            errorMsgList.add(String.format(EMPTY_ERROR_MSG, index, "下次检验/更换日期"));
        }
        if (StringUtils.isBlank(importAspSafeAttachmentsVo.getCertificatenumber())) {
            errorMsgList.add(String.format(EMPTY_ERROR_MSG, index, "证书/报告编号"));
        }
        // 校验时间格式是否正确
        if (StringUtils.isNotBlank(importAspSafeAttachmentsVo.getManufacturestr()) && dateFormatValidation(importAspSafeAttachmentsVo.getManufacturestr()) == null) {
            errorMsgList.add(String.format(DATE_FORMAT_ERROR_MSG, index, "出厂日期"));
        }
        // 校验时间格式是否正确
        if (StringUtils.isNotBlank(importAspSafeAttachmentsVo.getNextinspectionstr()) && dateFormatValidation(importAspSafeAttachmentsVo.getNextinspectionstr()) == null) {
            errorMsgList.add(String.format(DATE_FORMAT_ERROR_MSG, index, "下次检验/更换日期"));
        }
        // 校验时间格式是否正确
        if (StringUtils.isNotBlank(importAspSafeAttachmentsVo.getInspectionstr()) && dateFormatValidation(importAspSafeAttachmentsVo.getInspectionstr()) == null) {
            errorMsgList.add(String.format(DATE_FORMAT_ERROR_MSG, index, "检验/更换日期"));
        }
    }

    private Date dateFormatValidation(String strDate) {
        Date date = null;
        for (SimpleDateFormat simpleDateFormat : DATE_FORMAT_LIST) {
            try {
                date = simpleDateFormat.parse(strDate);
                break;
            } catch (Exception e) {
                log.info("时间格式不正确");
            }
        }
        return date;
    }

    /**
     * vo 转 do
     *
     * @param checkArea
     * @param vo
     * @return
     */
    private AspSafeAttachmentsDo voToDo(ImportAspSafeAttachmentsVo vo,
                                        Map<String, String> checkAreaMap,
                                        Map<String, String> orgMap,
                                        Map<String, String> userMap,
                                        String tenantId) {
        AspSafeAttachmentsDo aspSafeAttachmentsDo = new AspSafeAttachmentsDo();
        BeanUtils.copyProperties(vo, aspSafeAttachmentsDo);
        aspSafeAttachmentsDo.setId(SecurityUtil.getUUID());
        aspSafeAttachmentsDo.setTenantid(tenantId);
        aspSafeAttachmentsDo.setCreatedate(new Date());
        aspSafeAttachmentsDo.setMainid(checkAreaMap.get(vo.getTreeName()));
        aspSafeAttachmentsDo.setUseshopid(orgMap.get(vo.getUseshop()));
        // 时间转换
        if (StringUtils.isNotBlank(vo.getManufacturestr())) {
            aspSafeAttachmentsDo.setManufacturedate(dateFormatValidation(vo.getManufacturestr()));
        }

        aspSafeAttachmentsDo.setInspectiondate(dateFormatValidation(vo.getInspectionstr()));
        aspSafeAttachmentsDo.setNextinspectiondate(dateFormatValidation(vo.getNextinspectionstr()));
        if (StringUtils.isNotBlank(vo.getResponsible())) {
            String ids = Arrays.stream(vo.getResponsible().split(",")).map(username -> userMap.get(username)).collect(Collectors.joining(",0"));
            // 设置责任人ID
            aspSafeAttachmentsDo.setResponsibleid(ids);
        }

        LocalDate date1 = aspSafeAttachmentsDo.getNextinspectiondate().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
        long daysBetween = ChronoUnit.DAYS.between(LocalDate.now(), date1);
        if (daysBetween <= 30) {
            aspSafeAttachmentsDo.setReminderstate(HIGH);
        } else if (daysBetween <= 90) {
            aspSafeAttachmentsDo.setReminderstate(MIDDLE);
        } else {
            aspSafeAttachmentsDo.setReminderstate(LOW);
        }
        return aspSafeAttachmentsDo;
    }

}




