package com.ktg.iscs.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ktg.common.core.domain.entity.SysUser;
import com.ktg.common.utils.DateUtils;
import com.ktg.common.utils.bean.BeanUtils;
import com.ktg.iscs.domain.*;
import com.ktg.iscs.domain.dto.checkPlan.AddCheckPlanDTO;
import com.ktg.iscs.domain.dto.plan.PlanDTO;
import com.ktg.iscs.mapper.IsMaterialsCheckPlanMapper;
import com.ktg.iscs.service.*;
import com.ktg.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 物资检查计划Service业务层处理
 *
 * @author cgj
 * @date 2025-01-14
 */
@Service
public class IsMaterialsCheckPlanServiceImpl extends ServiceImpl<IsMaterialsCheckPlanMapper, IsMaterialsCheckPlan> implements IIsMaterialsCheckPlanService {

    @Autowired
    private IsMaterialsCheckPlanMapper isMaterialsCheckPlanMapper;
    @Autowired
    private IIsMaterialsPlanCabinetService iIsMaterialsPlanCabinetService;
    // @Value("${mail.checkPlan}")
    // private String checkPlan;
    @Autowired
    private IIsMailTemplateService iIsMailTemplateService;
    @Autowired
    private IIsMailNotifyConfigService isMailNotifyConfigService;
    @Autowired
    private IIsMaterialsCabinetService iIsMaterialsCabinetService;
    @Autowired
    private ISysUserService iSysUserService;
    @Autowired
    private IIsMailSendTaskItemService iIsMailSendTaskItemService;
    @Autowired
    private IIsSystemAttributeService isSystemAttributeService;
    @Autowired
    private IIsMaterialsCheckRecordService isMaterialsCheckRecordService;

    @Override
    public Page<IsMaterialsCheckPlan> getIsMaterialsCheckPlanPage(Page<IsMaterialsCheckPlan> page, PlanDTO dto) {
        Page<IsMaterialsCheckPlan> result = isMaterialsCheckPlanMapper.getIsMaterialsCheckPlanPage(page, dto);
        if (!result.getRecords().isEmpty()) {
            // 分页中所有的计划
            List<Long> planIds = result.getRecords().stream().map(IsMaterialsCheckPlan::getPlanId).collect(Collectors.toList());
            // 计划中所有的关联柜子
            List<IsMaterialsPlanCabinet> planCabinets = iIsMaterialsPlanCabinetService.list(Wrappers.<IsMaterialsPlanCabinet>lambdaQuery()
                    .in(IsMaterialsPlanCabinet::getPlanId, planIds));
            // 柜子的id
            List<Long> cabinetIds = planCabinets.stream().map(IsMaterialsPlanCabinet::getCabinetId).collect(Collectors.toList());
            // 柜子的详情
            List<IsMaterialsCabinet> cabinets = iIsMaterialsCabinetService.list(Wrappers.<IsMaterialsCabinet>lambdaQuery()
                    .in(IsMaterialsCabinet::getCabinetId, cabinetIds));
            for (IsMaterialsCheckPlan record : result.getRecords()) {
                List<Long> cabinetId = planCabinets.stream().filter(o -> o.getPlanId().equals(record.getPlanId()))
                        .map(IsMaterialsPlanCabinet::getCabinetId).collect(Collectors.toList());
                String cabinetName = cabinets.stream()
                        .filter(cabinet -> cabinetId.contains(cabinet.getCabinetId()))
                        .map(IsMaterialsCabinet::getCabinetName)
                        .collect(Collectors.joining(","));
                record.setCabinetName(cabinetName);
            }
        }
        return result;
    }

    @Transactional
    @Override
    public Boolean insertIsMaterialsCheckPlan(AddCheckPlanDTO dto) {
        // 1.断言检测
        Assert.notNull(dto.getPlanDate(), "检查日期不可为空!");
        Assert.notNull(dto.getCheckUserId(), "检查员不可为空!");
        Assert.isFalse(dto.getCabinetIds().isEmpty(), "请选择需要检查的柜子!");
        // 2.开始新增计划
        IsMaterialsCheckPlan materialsCheckPlan = BeanUtils.toBean(dto, IsMaterialsCheckPlan.class);
        // 2.1开始生成文件名称尾缀
        String jobName = materialsCheckPlan.getPlanName();
        int counter = 1;
        String rname = materialsCheckPlan.getPlanName();
        while (!list(Wrappers.<IsMaterialsCheckPlan>lambdaQuery().eq(IsMaterialsCheckPlan::getPlanName, jobName)).isEmpty()) {
            jobName = rname + "(" + counter + ")";
            counter++;
        }
        materialsCheckPlan.setPlanName(jobName);
        save(materialsCheckPlan);
        // 3.开始新增计划和物资柜的关联关系
        List<IsMaterialsPlanCabinet> isMaterialsPlanCabinets = new ArrayList<>();
        for (Long cabinetId : dto.getCabinetIds()) {
            IsMaterialsPlanCabinet isMaterialsPlanCabinet = new IsMaterialsPlanCabinet();
            isMaterialsPlanCabinet.setPlanId(materialsCheckPlan.getPlanId());
            isMaterialsPlanCabinet.setCabinetId(cabinetId);
            isMaterialsPlanCabinet.setCheckUserId(dto.getCheckUserId());
            isMaterialsPlanCabinets.add(isMaterialsPlanCabinet);
            iIsMaterialsPlanCabinetService.save(isMaterialsPlanCabinet);
        }
        // iIsMaterialsPlanCabinetService.saveBatch(isMaterialsPlanCabinets);
        // 4.开始计算倒计时，给检查员发送邮件
        addMail(dto, materialsCheckPlan);
        return true;
    }

    private Boolean addMail(AddCheckPlanDTO dto, IsMaterialsCheckPlan materialsCheckPlan) {
        // 4.1获取模板
        IsSystemAttribute isSystemAttributeByKey = isSystemAttributeService.getIsSystemAttributeByKey("sys.template.check_plan");
        Assert.isFalse(isSystemAttributeByKey == null, "请在基础数据中配置物资检查计划模板！");
        IsMailTemplate template = iIsMailTemplateService.getOne(Wrappers.<IsMailTemplate>lambdaQuery()
                .eq(IsMailTemplate::getTemplateCode, isSystemAttributeByKey.getSysAttrValue()));
        // 4.2获取配置的时间
        IsMailNotifyConfig notifyConfig = isMailNotifyConfigService.getOne(Wrappers.<IsMailNotifyConfig>lambdaQuery()
                .eq(IsMailNotifyConfig::getTemplateCode, isSystemAttributeByKey.getSysAttrValue()));
        // 4.2.1无论是不是新增都先查一下有没有邮件，有邮件看下发了没有，没有发也没取消就删掉重新增
        if (template != null) {
            List<IsMailSendTaskItem> notSendMails = iIsMailSendTaskItemService.list(Wrappers.<IsMailSendTaskItem>lambdaQuery()
                    .eq(IsMailSendTaskItem::getEmailTemplateId, template.getTemplateId())
                    .eq(IsMailSendTaskItem::getBelongId, materialsCheckPlan.getPlanId())
                    .eq(IsMailSendTaskItem::getSendStatus, "0")
                    .eq(IsMailSendTaskItem::getIsCancelled, "0"));
            if (!notSendMails.isEmpty()) {
                List<Long> notSendMailIds = notSendMails.stream().map(IsMailSendTaskItem::getMailId).collect(Collectors.toList());
                iIsMailSendTaskItemService.removeBatchByIds(notSendMailIds);
            }
        }
        // 4.3判断柜子是否激活，激活才有效
        if (template != null && notifyConfig != null && "1".equals(notifyConfig.getStatus())) {
            // 5.1新增预发送邮件到数据库
            // 理应的发送时间计算
            Date newDateTime = DateUtils.getNewDateTime(dto.getPlanDate(), notifyConfig.getReminderTime());
            // 5.1.1柜子的详情
            List<IsMaterialsCabinet> cabinets = iIsMaterialsCabinetService.list(Wrappers.<IsMaterialsCabinet>lambdaQuery()
                    .in(IsMaterialsCabinet::getCabinetId, dto.getCabinetIds()));
            String cabinetNameStr = cabinets.stream().map(IsMaterialsCabinet::getCabinetName).collect(Collectors.joining(","));
            // 5.1.2检察员信息
            SysUser user = iSysUserService.getById(dto.getCheckUserId());
            // 5.3新增邮件任务
            // 5.4整理可配置的字段
            HashMap<String, String> map = new HashMap<>();
            map.put("[计划名称]", dto.getPlanName());
            map.put("[计划日期]", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, dto.getPlanDate()));
            map.put("[物资柜]", cabinetNameStr);
            map.put("[检察员]", user.getNickName());
            map.put("[发件人]", isSystemAttributeService.getIsSystemAttributeByKey("info.mail.name").getSysAttrValue());
            map.put("[公司名称]", isSystemAttributeService.getIsSystemAttributeByKey("info.mail.company").getSysAttrValue());
            map.put("[邮件发送时间]", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, newDateTime));
            // 邮件实体
            IsMailSendTaskItem taskItem = new IsMailSendTaskItem();
            taskItem.setSendToUserId(dto.getCheckUserId());
            taskItem.setEmailTemplateId(template.getTemplateId());
            taskItem.setScheduledSendTime(newDateTime);
            taskItem.setBelongId(materialsCheckPlan.getPlanId());
            taskItem.setSendStatus(0);
            taskItem.setIsCancelled(0);
            iIsMailSendTaskItemService.insertIsMailSendTaskItem(taskItem, map);
        }
        return true;
    }


    @Override
    public Boolean updateIsMaterialsCheckPlan(AddCheckPlanDTO dto) {
        // 1.断言检测
        Assert.notNull(dto.getPlanId(), "主键ID不可为空!");
        Assert.notNull(dto.getPlanDate(), "检查日期不可为空!");
        Assert.notNull(dto.getCheckUserId(), "检查员不可为空!");
        Assert.isFalse(dto.getCabinetIds().isEmpty(), "请选择需要检查的柜子!");
        List<IsMaterialsCheckPlan> list = list(Wrappers.<IsMaterialsCheckPlan>lambdaQuery()
                .eq(IsMaterialsCheckPlan::getPlanName, dto.getPlanName())
                .ne(IsMaterialsCheckPlan::getPlanId, dto.getPlanId()));
        Assert.isTrue(list.isEmpty(), "该名称已被使用!");
        // 2.开始新增计划
        IsMaterialsCheckPlan materialsCheckPlan = BeanUtils.toBean(dto, IsMaterialsCheckPlan.class);
        updateById(materialsCheckPlan);
        // 3.开始新增计划和物资柜的关联关系
        // 3.1先删除，再新增
        iIsMaterialsPlanCabinetService.remove(Wrappers.<IsMaterialsPlanCabinet>lambdaQuery()
                .eq(IsMaterialsPlanCabinet::getPlanId, dto.getPlanId()));
        List<IsMaterialsPlanCabinet> isMaterialsPlanCabinets = new ArrayList<>();
        for (Long cabinetId : dto.getCabinetIds()) {
            IsMaterialsPlanCabinet isMaterialsPlanCabinet = new IsMaterialsPlanCabinet();
            isMaterialsPlanCabinet.setPlanId(materialsCheckPlan.getPlanId());
            isMaterialsPlanCabinet.setCabinetId(cabinetId);
            isMaterialsPlanCabinet.setCabinetId(dto.getCheckUserId());
            isMaterialsPlanCabinets.add(isMaterialsPlanCabinet);
            iIsMaterialsPlanCabinetService.save(isMaterialsPlanCabinet);
        }
        // iIsMaterialsPlanCabinetService.saveBatch(isMaterialsPlanCabinets);
        // 4.邮件也是先删除再新增
        addMail(dto, materialsCheckPlan);
        return true;
    }

    @Transactional
    @Override
    public Boolean deleteIsMaterialsCheckPlanByPlanIds(String planIds) {
        Assert.notBlank(planIds, "请选择需要删除的数据!");
        Long[] longIds = Convert.toLongArray(planIds);
        removeBatchByIds(Arrays.asList(longIds));
        // 开始删除关联的物资柜数据
        iIsMaterialsPlanCabinetService.remove(Wrappers.<IsMaterialsPlanCabinet>lambdaQuery()
                .in(IsMaterialsPlanCabinet::getPlanId, longIds));
        // 取消关联的发送邮件
        IsMailTemplate template = iIsMailTemplateService.getOne(Wrappers.<IsMailTemplate>lambdaQuery()
                .eq(IsMailTemplate::getTemplateCode, isSystemAttributeService.getIsSystemAttributeByKey("sys.template.check_plan").getSysAttrValue()));
        if (template != null) {
            iIsMailSendTaskItemService.update(Wrappers.<IsMailSendTaskItem>lambdaUpdate()
                    .eq(IsMailSendTaskItem::getEmailTemplateId, template.getTemplateId())
                    .in(IsMailSendTaskItem::getBelongId, planIds)
                    .eq(IsMailSendTaskItem::getSendStatus, "0")
                    .set(IsMailSendTaskItem::getIsCancelled, "1")
                    .set(IsMailSendTaskItem::getCancelTime, new Date()));
        }
        // 删除检查记录
        isMaterialsCheckRecordService.remove(Wrappers.<IsMaterialsCheckRecord>lambdaQuery()
                .in(IsMaterialsCheckRecord::getPlanId, longIds));
        return true;
    }

    @Override
    public IsMaterialsCheckPlan selectIsMaterialsCheckPlanById(Long planId) {
        IsMaterialsCheckPlan byId = getById(planId);
        if (byId != null) {
            List<IsMaterialsPlanCabinet> list = iIsMaterialsPlanCabinetService.list(Wrappers.<IsMaterialsPlanCabinet>lambdaQuery()
                    .eq(IsMaterialsPlanCabinet::getPlanId, planId));
            byId.setCabinetIds(list.stream().map(IsMaterialsPlanCabinet::getCabinetId).collect(Collectors.toList()));
        }
        return byId;
    }


}
