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

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rongwei.bscommon.sys.dao.CommonDao;
import com.rongwei.bscommon.sys.dao.EquLubricationPlanMapperDao;
import com.rongwei.bscommon.sys.service.EquLubricationPlanDetailService;
import com.rongwei.bscommon.sys.service.EquLubricationPlanService;
import com.rongwei.bscommon.sys.service.EquipmentSendNotifyService;
import com.rongwei.bscommon.sys.utils.ExceptionUtils;
import com.rongwei.bsentity.domain.*;
import com.rongwei.rwadmincommon.system.domain.SysDictDo;
import com.rongwei.rwadmincommon.system.service.SysDictService;
import com.rongwei.rwcommon.base.BaseDo;
import com.rongwei.rwcommon.base.R;
import com.rongwei.rwcommon.utils.SecurityUtil;
import com.rongwei.rwcommon.utils.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

import static com.rongwei.safecommon.utils.CXCommonUtils.streamCodeGeneration;

/**
 * <p>
 * 设备子系统——润滑计划标准 服务实现类
 * </p>
 *
 * @author fpy
 * @since 2024-01-12
 */
@Service
public class EquLubricationPlanServiceImpl extends ServiceImpl<EquLubricationPlanMapperDao, EquLubricationPlanDo> implements EquLubricationPlanService {

    private final Logger log = LoggerFactory.getLogger(this.getClass().getName());

    @Autowired
    private EquLubricationPlanService equLubricationPlanService;

    @Autowired
    private CommonDao commonDao;

    @Autowired
    private EquLubricationPlanDetailService equLubricationPlanDetailService;

    @Autowired
    private EquLubricationPlanMapperDao lubricationPlanMapperDao;

    @Autowired
    private EquLubricationTaskManagementServiceImpl equLubricationTaskManagementService;
    @Autowired
    private EquLubricationTaskDetailServiceImpl equLubricationTaskDetailService;
    @Autowired
    private EquipmentSendNotifyService equipmentSendNotifyService;
    @Autowired
    private SysDictService sysDictService;

    /**
     * 启用
     */
    public static final String ENABLE = "10";
    /**
     * 未润滑
     */
    public static final String UNLUBRICATED = "n";
    /**
     * 润滑任务状态待完成
     */
    public static final String TASK_STATUS_TO_BE_COMPLETED = "10";

    /**
     * 半年
     */
    public static final String HALF_YEAR = "70";
    /**
     * 季度
     */
    public static final String QUARTER = "60";
    /**
     * 每月
     */
    public static final String MONTH = "40";
    /**
     * 每周
     */
    public static final String WEEK = "20";
    /**
     * 每季度的第一个月
     */
    public static final List<Integer> QUARTER_MONTH = new ArrayList<Integer>() {{
        add(1);
        add(4);
        add(7);
        add(10);
    }};
    public static final List<Integer> HALF_YEAR_MONTH = new ArrayList<Integer>() {{
        add(1);
        add(7);
    }};


    @Override
    public void wordExportLubrication(Map<String, Object> parameter, HttpServletResponse response) {
        log.info("开始导出润滑明细");
        String tenantId = parameter.get("userTopOrg").toString();
        List<EquLubricationPlanDetailVo> planDetailList = equLubricationPlanDetailService.queryAllDetailList(tenantId);
        List<SysDictDo> isEnableType = sysDictService.getDictsByType("lubricationIsEnable");
        List<SysDictDo> frequencyByType = sysDictService.getDictsByType("lubricationFrequency");
        try {
            response.setContentType("application/octet-stream");
            // 读取模板文件
            TemplateExportParams params = new TemplateExportParams("template/润滑明细模板.xls", 0);
            Map<String, Object> dataMap = new HashMap<>(16);
            List<Map<String,Object>> dataList = new ArrayList<>();
            for (EquLubricationPlanDetailVo equLubricationPlanDetailVo : planDetailList) {
                String isEnable = "";
                if (StringUtils.isNotBlank(equLubricationPlanDetailVo.getEnablestatus())) {
                    isEnable = isEnableType.stream().filter(dictDo -> equLubricationPlanDetailVo.getEnablestatus().contains(dictDo.getValue()))
                            .map(SysDictDo::getName).collect(Collectors.joining(","));
                    equLubricationPlanDetailVo.setEnablestatus(isEnable);
                }
                String frequency = "";
                if (StringUtils.isNotBlank(equLubricationPlanDetailVo.getFrequency())) {
                    frequency = frequencyByType.stream().filter(dictDo -> equLubricationPlanDetailVo.getFrequency().contains(dictDo.getValue()))
                            .map(SysDictDo::getName).collect(Collectors.joining(","));
                    equLubricationPlanDetailVo.setFrequency(frequency);
                }
                dataList.add(JSONObject.parseObject(JSONObject.toJSONString(equLubricationPlanDetailVo), Map.class));
            }
            dataMap.put("list",dataList);
            Workbook workbook = ExcelExportUtil.exportExcel(params,dataMap);
            workbook.write(response.getOutputStream());
            workbook.close();
        }catch (Exception e){
            ExceptionUtils.printExceptionDetail(e,"润滑明细导出异常");
        }
    }

    /**
     * 根据设备ID修改润滑标准状态
     *
     * @param equipmentId
     * @return
     * @date 2024/1/16 17:36
     * @author shangmi
     *
     */

    @Override
    public void updateStateByEquId(String equipmentId) {
        LambdaUpdateWrapper<EquLubricationPlanDo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(EquLubricationPlanDo::getEquipmentid, equipmentId).set(EquLubricationPlanDo::getEnablestatus, "20");
        lubricationPlanMapperDao.update(null, updateWrapper);
    }

    /**
     * 润滑计划标准定时任务
     * 在每月一号和每周的周一执行
     *
     * @return
     */
    @Override
    public R timedTask() {
        Calendar calendar = Calendar.getInstance(); // 获取当前时间的Calendar对象
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); // 获取星期几（1表示星期天，2表示星期一，依此类推）
        // 是否为周一
        boolean isMonday = dayOfWeek == Calendar.MONDAY;
        // 当前月份
        int currentMonth = calendar.get(Calendar.MONTH) + 1;
        int currentYear = calendar.get(Calendar.YEAR);
        boolean isFirstDayOfMonth = calendar.getActualMinimum(Calendar.DATE) == calendar.get(Calendar.DATE);
        // 是否为每月1号
        // 如果不是周一和每月一号 直接结束
        if (!isMonday && !isFirstDayOfMonth) {
            log.error("当前日期不是周一且不是1号");
            return R.ok();
        }
        // 获取计划明细
        List<EquLubricationPlanDo> planDoList = equLubricationPlanService.list(new LambdaQueryWrapper<EquLubricationPlanDo>()
                .eq(BaseDo::getDeleted, "0")
                .eq(EquLubricationPlanDo::getEnablestatus, ENABLE));
        if (planDoList.isEmpty()) {
            log.debug("暂无启用的定时任务");
            return R.ok();
        }
        List<String> planIds = planDoList.stream().map(EquLubricationPlanDo::getId).collect(Collectors.toList());
        // 获取到详细
        List<EquLubricationPlanDetailDo> detailDoList = equLubricationPlanDetailService.list(new LambdaQueryWrapper<EquLubricationPlanDetailDo>()
                .eq(BaseDo::getDeleted, "0").eq(EquLubricationPlanDetailDo::getEnablestatus, ENABLE)
                .in(EquLubricationPlanDetailDo::getMasterid, planIds)
                .last("and IFNULL(FREQUENCY,'')!=''"));
        if (detailDoList.isEmpty()) {
            log.debug("暂无启用的定时任务");
            return R.ok();
        }
        generateTaskData(planDoList, detailDoList, isMonday, isFirstDayOfMonth, currentMonth, currentYear);
        return R.ok();
    }

    /**
     * 生成润滑任务
     *
     * @param planDoList        润滑计划
     * @param detailDoList      润滑计划子表
     * @param isMonday          是否为周一
     * @param isFirstDayOfMonth 是否为每月一号
     * @param currentMonth      当前月份
     */
    public void generateTaskData(List<EquLubricationPlanDo> planDoList, List<EquLubricationPlanDetailDo> detailDoList,
                                 boolean isMonday, boolean isFirstDayOfMonth, int currentMonth, int currentYear) {
        List<EquLubricationTaskManagementDo> taskList = new ArrayList<>();
        List<EquLubricationTaskDetailDo> taskDetailList = new ArrayList<>();
        // FIXME:XH add 2024/1/23 按照要求 统一设备出现润滑部位相同的情况 不做任何处理按照原逻辑生成
        // 循环计划
        planDoList.forEach(plan -> {
            List<EquLubricationPlanDetailDo> detailList = detailDoList.stream().filter(info -> info.getMasterid().equals(plan.getId()))
                    .filter(info -> checkGenerateData(info, isMonday, isFirstDayOfMonth, currentMonth))
                    .collect(Collectors.toList());

            assembleTaskManagementDo(taskList, taskDetailList, plan, detailList, currentMonth, currentYear);
        });
        // 数据存表
        equLubricationTaskManagementService.saveBatch(taskList, 50);
        equLubricationTaskDetailService.saveBatch(taskDetailList, 50);
        // 发送消息提醒
//        equipmentSendNotifyService.sendLubricationTaskNotify(taskList);
    }

    /**
     * 校验润滑部位是否需要生成 润滑任务
     *
     * @param equLubricationPlanDetailDo
     * @param isMonday                   是否为周一
     * @param isFirstDayOfMonth          是否为每月一号
     * @param currentMonth               当前月份
     * @return
     */
    public boolean checkGenerateData(EquLubricationPlanDetailDo equLubricationPlanDetailDo, boolean isMonday,
                                     boolean isFirstDayOfMonth,
                                     int currentMonth) {
        if (equLubricationPlanDetailDo.getNumber() == null || equLubricationPlanDetailDo.getNumber() <= 0) {
            return false;
        }
        // 是否需要生成
        boolean isGenerate = false;
        switch (equLubricationPlanDetailDo.getFrequency()) {
            case HALF_YEAR: // 每半年
                isGenerate = isFirstDayOfMonth && HALF_YEAR_MONTH.contains(currentMonth);
                break;
            case QUARTER: // 每季度
                isGenerate = isFirstDayOfMonth && QUARTER_MONTH.contains(currentMonth);
                break;
            case MONTH: // 每月
                isGenerate = isFirstDayOfMonth;
                break;
            case WEEK: // 每周 只有周一生成
                isGenerate = isMonday;
                break;
            default:
        }
        return isGenerate;
    }

    /**
     * 生成润滑任务数据
     *
     * @param taskList             润滑任务主表
     * @param taskDetailList       润滑任务子表
     * @param equLubricationPlanDo 润滑计划
     * @param detailList           润滑计划明细
     * @param currentMonth         当前月份
     * @param currentYear          当前年份
     */
    public void assembleTaskManagementDo(List<EquLubricationTaskManagementDo> taskList,
                                         List<EquLubricationTaskDetailDo> taskDetailList,
                                         EquLubricationPlanDo equLubricationPlanDo,
                                         List<EquLubricationPlanDetailDo> detailList,
                                         int currentMonth,
                                         int currentYear) {
        if(detailList.isEmpty()){
            return;
        }
        // 获取该计划中次数最大的数据
        Integer maximumFrequency = detailList.stream().map(EquLubricationPlanDetailDo::getNumber).max(Integer::compareTo).get();
        // 任务主表实体
        EquLubricationTaskManagementDo equLubricationTaskManagementDo = null;
        // 任务子表实体
        EquLubricationTaskDetailDo equLubricationTaskDetailDo = null;
        // 需要生成任务的计划明细数据
        List<EquLubricationPlanDetailDo> filterData;
        for (int i = 0; i < maximumFrequency; i++) {
            // 获取计划明细中次数小于当前次数的数据
            int currentNum = i + 1;
            filterData = detailList.stream().filter(info -> info.getNumber() >= currentNum).collect(Collectors.toList());
            // 生成主表数据
            equLubricationTaskManagementDo = assembleMasterMeterDo(equLubricationTaskManagementDo, equLubricationPlanDo, filterData, currentMonth, currentYear);
            // 生成子表数据
            taskDetailList.addAll(assembleSubtableDataDo(equLubricationTaskManagementDo, equLubricationTaskDetailDo, filterData));
            taskList.add(equLubricationTaskManagementDo);
        }

    }


    /**
     * 生成润滑任务主表数据
     *
     * @return
     */
    public EquLubricationTaskManagementDo assembleMasterMeterDo(EquLubricationTaskManagementDo equLubricationTaskManagementDo,
                                                                EquLubricationPlanDo equLubricationPlanDo,
                                                                List<EquLubricationPlanDetailDo> equLubricationTaskDetailDos,
                                                                int currentMonth, int currentYear) {
        equLubricationTaskManagementDo = new EquLubricationTaskManagementDo();
        equLubricationTaskManagementDo.setId(SecurityUtil.getUUID());
        equLubricationTaskManagementDo.setTenantid(equLubricationPlanDo.getTenantid());
        String taskNumber = streamCodeGeneration("equ_lubrication_task_management_code", "@{date:yyyy}@{serialNumber:#00000}",
                "date:yyyy", equLubricationPlanDo.getTenantid());
        equLubricationTaskManagementDo.setTasknumber(taskNumber);
        equLubricationTaskManagementDo.setYear(currentYear);
        equLubricationTaskManagementDo.setMonth(currentMonth);
        equLubricationTaskManagementDo.setBelongfactory(equLubricationPlanDo.getBelongfactory());
        equLubricationTaskManagementDo.setEquipment(equLubricationPlanDo.getEquipment());
        equLubricationTaskManagementDo.setEquipmentnumber(equLubricationPlanDo.getEquipmentnumber());
        equLubricationTaskManagementDo.setLubricator(equLubricationTaskDetailDos.stream()
                .map(info->info.getLubricator().split(","))
                .flatMap(Arrays::stream)
               .distinct().collect(Collectors.joining(",")));
//        equLubricationTaskManagementDo.setCompletedate();
        equLubricationTaskManagementDo.setTaskstatus(TASK_STATUS_TO_BE_COMPLETED);
        equLubricationTaskManagementDo.setLubricatorid(equLubricationTaskDetailDos.stream()
                .map(info->info.getLubricatorid().split(","))
                .flatMap(Arrays::stream)
               .distinct().collect(Collectors.joining(",")));
        equLubricationTaskManagementDo.setEquipmentid(equLubricationPlanDo.getEquipmentid());
        equLubricationTaskManagementDo.setEquipmentworkshopid(equLubricationPlanDo.getEquipmentworkshopid());
        equLubricationTaskManagementDo.setEquipmentworkshop(equLubricationPlanDo.getEquipmentworkshop());
        equLubricationTaskManagementDo.setTaskfrequency(equLubricationTaskDetailDos.stream()
                .map(EquLubricationPlanDetailDo::getFrequency).distinct().collect(Collectors.joining(",")));
        return equLubricationTaskManagementDo;
    }

    /**
     * 生成任务明细表数据
     *
     * @param equLubricationTaskManagementDo 任务主表实体
     * @param equLubricationTaskDetailDo     任务子表实体
     * @param equLubricationTaskDetailDos    任务计划
     * @return
     */
    public List<EquLubricationTaskDetailDo> assembleSubtableDataDo(EquLubricationTaskManagementDo equLubricationTaskManagementDo,
                                                                   EquLubricationTaskDetailDo equLubricationTaskDetailDo,
                                                                   List<EquLubricationPlanDetailDo> equLubricationTaskDetailDos) {
        List<EquLubricationTaskDetailDo> saveList = new ArrayList<>();
        for (EquLubricationPlanDetailDo lubricationTaskDetailDo : equLubricationTaskDetailDos) {
            equLubricationTaskDetailDo = new EquLubricationTaskDetailDo();
            equLubricationTaskDetailDo.setId(SecurityUtil.getUUID());
            equLubricationTaskDetailDo.setTenantid(equLubricationTaskManagementDo.getTenantid());
            equLubricationTaskDetailDo.setMasterid(equLubricationTaskManagementDo.getId());
            equLubricationTaskDetailDo.setLubricationposition(lubricationTaskDetailDo.getLubricationposition());
            equLubricationTaskDetailDo.setLubricants(lubricationTaskDetailDo.getLubricants());
            equLubricationTaskDetailDo.setLubricationamount(lubricationTaskDetailDo.getLubricationamount());
            equLubricationTaskDetailDo.setFrequency(lubricationTaskDetailDo.getFrequency());
            equLubricationTaskDetailDo.setLubricatorid(lubricationTaskDetailDo.getLubricatorid());
            equLubricationTaskDetailDo.setLubricator(lubricationTaskDetailDo.getLubricator());
            equLubricationTaskDetailDo.setEnablestatus(TASK_STATUS_TO_BE_COMPLETED);
            equLubricationTaskDetailDo.setIslubricationcompleted(UNLUBRICATED);
            equLubricationTaskDetailDo.setStandardnumber(lubricationTaskDetailDo.getStandardnumber());
            saveList.add(equLubricationTaskDetailDo);
        }
        return saveList;
    }

}
