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

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rongwe.scentity.domian.AspSafeAttachmentsDo;
import com.rongwe.scentity.vo.CheckAreaVo;
import com.rongwe.scentity.vo.ImportAspSafeAttachmentsVo;
import com.rongwe.scentity.vo.UserMailOrgVo;
import com.rongwei.rwadmincommon.system.domain.SysOrganizationDo;
import com.rongwei.rwadmincommon.system.domain.SysUserDo;
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.rwcommonentity.commonservers.domain.SysFileItemDo;
import com.rongwei.safecommon.utils.JSCommonUtils;
import com.rongwei.sfcommon.sys.dao.AspSafeAttachmentsDao;
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 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.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;

/**
 *
 */
@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");
    }};
    /**
     * 特种设备管理员
     */
    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;

    @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>>();
        dataMap.forEach((k, v) -> {
            //获取工厂对应的 安全管理员和特种设备管理员
            List<UserMailOrgVo> userInfO = saveCheckCommonDao.getUserInfoByTenantIdAndRoleCode(k, ROLE_CODE_LIST);
            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 <= 30) {
                    data.setReminderstate(HIGH);
                    alertUser = userInfO.stream().map(UserMailOrgVo::getId).collect(Collectors.toList());
                    sendNotifyMap.put(data, alertUser);
                } else if (daysBetween <= 90) {
                    alertUser = userInfO.stream().filter(user -> SPECIAL_EQUIPMENT_ADMINISTRATOR.equals(user.getRoleCode())).map(UserMailOrgVo::getId).collect(Collectors.toList());
                    sendNotifyMap.put(data, alertUser);
                    data.setReminderstate(MIDDLE);
                } else {

                    data.setReminderstate(LOW);
                }

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

    /**
     * 发送消息提醒
     *
     * @param sendNotifyMap
     */
    public void sendNotify(Map<AspSafeAttachmentsDo, List<String>> sendNotifyMap) {
        sendNotifyMap.forEach((k, v) -> {
            // 发送消息提醒
            JSCommonUtils.sendNotify(SAFETY_ATTACHMENT_VERIFICATION_TITLE,
                    String.format(SAFETY_ATTACHMENT_VERIFICATION_CONTENT, k.getName(), k.getNumber(), k.getInspectiondate(),
                            k.getNextinspectiondate(), k.getResponsible()), null, v.stream().distinct().collect(Collectors.toList()),
                    k.getId(), SAFETY_ATTACHMENT_VERIFICATION, false);
        });
    }

    /**
     * 导入excel
     *
     * @param queryParameter
     * @return
     */
    @SneakyThrows
    @Override
    public R importExcel(Map<String, String> queryParameter) {
        String fileId = queryParameter.getOrDefault("fileId", "");
        JSCommonUtils.parameterCheck(() -> StringUtils.isBlank(fileId), "请上传文件", "文件ID为空");
        SysFileItemDo fileItemDo = saveCheckCommonDao.getFileItemByID(fileId);
        JSCommonUtils.parameterCheck(() -> fileItemDo == null, "文件解析有误!请联系管理员", "无法根据文件ID:{},获取到文件信息", fileId);
        String realPath = fileItemDo.getFullpath();
        JSCommonUtils.parameterCheck(() -> StringUtils.isBlank(realPath), "文件解析有误!请联系管理员", "根据文件ID:{},无法获取到文件路径", fileId);
        File file = new File(realPath);
        JSCommonUtils.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 = JSCommonUtils.getCurrentUser();
        String tenantId = currentUser.getOrganizationDoList().get(0).getFullpid().split(",")[1];
        //获取区域信息
        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;
    }

}




