package com.casic.missiles.service.Impl.meter;


import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.util.DateUtils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.casic.missiles.core.application.service.AbstractDictService;
import com.casic.missiles.core.base.service.IBaseExportService;
import com.casic.missiles.core.model.auth.AuthUser;
import com.casic.missiles.core.shiro.ShiroKit;
import com.casic.missiles.dto.IdDTO;
import com.casic.missiles.dto.meter.MeterCertificateDto;
import com.casic.missiles.dto.ReturnDTO;
import com.casic.missiles.dto.ReturnUtil;
import com.casic.missiles.dto.meter.MeterCertificateImport;
import com.casic.missiles.dto.meter.MeterStaffRequest;
import com.casic.missiles.enums.*;
import com.casic.missiles.enums.meter.MeterDictEnum;
import com.casic.missiles.enums.meter.MeterRoleTypeEnum;
import com.casic.missiles.enums.workbench.MessageSourceModuleEnum;
import com.casic.missiles.enums.workbench.MessageTypeEnum;
import com.casic.missiles.exception.BusinessException;
import com.casic.missiles.mapper.meter.MeterCertificateMapper;
import com.casic.missiles.mapper.meter.MeterStaffMapper;
import com.casic.missiles.mapper.sys.UserInfoMapper;
import com.casic.missiles.mapper.workbench.WorkbenchRemindMessageMapper;
import com.casic.missiles.model.meter.MeterCertificate;
import com.casic.missiles.model.meter.MeterStaff;
import com.casic.missiles.model.system.UserInfo;
import com.casic.missiles.model.workbench.WorkbenchRemindMessage;
import com.casic.missiles.service.meter.MeterCertificateService;
import com.casic.missiles.service.system.IMessagePushService;
import com.casic.missiles.service.workbench.IWorkbenchRemindMessageService;
import com.casic.missiles.utils.ExportUtils;
import com.casic.missiles.utils.MinioUtil;
import com.casic.missiles.utils.WebSocket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import static com.casic.missiles.service.Impl.meter.MeterStaffServiceImpl.isDateFormat;

@Service("MeterCertificateService")
@Slf4j
public class MeterCertificateServiceImpl extends ServiceImpl<MeterCertificateMapper, MeterCertificate> implements MeterCertificateService {

    @Resource
    private MeterCertificateMapper meterCertificateMapper;

    @Resource
    private MeterStaffMapper meterStaffMapper;

    @Resource
    private WebSocket webSocket;

    @Resource
    private WorkbenchRemindMessageMapper messageMapper;

    @Resource
    private AbstractDictService dictService;

    @Resource
    private IWorkbenchRemindMessageService messageService;

    @Resource
    private MinioUtil minioUtil;

    @Resource
    private IBaseExportService iBaseExportService;

    @Resource
    private UserInfoMapper userInfoMapper;

    @Override
    public ReturnDTO<MeterCertificateDto> queryCertificateList(Page<MeterCertificateDto> page , MeterStaffRequest meterStaffRequest) {
        Page<MeterCertificateDto> meterCertificateDtoPage = meterCertificateMapper.queryCertificateList(page, meterStaffRequest);
        meterCertificateDtoPage.setRecords(supplementList(meterCertificateDtoPage.getRecords()));
        return ReturnUtil.success(meterCertificateDtoPage);
    }

    @Override
    public ReturnDTO addStaffCertificate(List<MeterCertificate> list) {
        if(this.saveBatch(list)){
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public ReturnDTO<MeterCertificate> queryStaffCertificateInfo(IdDTO idDto) {
        // 通过id获取证书信息
        MeterCertificate meterCertificate = meterCertificateMapper.selectById(idDto.getId());
        // 通过证书信息中的staffId获取对应的人员信息
        MeterStaff meterStaff = meterStaffMapper.selectStaffInfo(meterCertificate.getStaffId());
        meterCertificate.setMeterStaff(meterStaff);
        return ReturnUtil.success(meterCertificate);
    }

    @Override
    public ReturnDTO updateStaffCertificateInfo(MeterCertificate meterCertificate) {
        if(meterCertificateMapper.updateById(meterCertificate)>0){
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public void exportCertificateList(MeterStaffRequest meterStaffRequest, HttpServletResponse response) {
        try {
            List<MeterCertificateDto> meterCertificateList;
            if(!CollectionUtils.isEmpty(meterStaffRequest.getIds())){
                MeterStaffRequest request = new MeterStaffRequest();
                request.setIds(meterStaffRequest.getIds());
                meterCertificateList = supplementList(meterCertificateMapper.queryCertificateList(request));
            }else{
                meterCertificateList = supplementList(meterCertificateMapper.queryCertificateList(meterStaffRequest));
            }
            meterCertificateList.forEach(bean->{
                bean.setSex(bean.getSex().equals("2")?"女":"男");
                bean.setCertificateStatus(bean.getCertificateStatus().equals("0")?"正常":"已失效");
            });
            iBaseExportService.exportExcel(response, MeterCertificateDto.class,meterCertificateList, ExportEnum.STAFF_CERTIFICATE.getSheetName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public ReturnDTO deleteCertificate(IdDTO idDto) {
        if(meterCertificateMapper.deleteById(idDto.getId())>0){
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public Page<WorkbenchRemindMessage> queryMessageList(Page<WorkbenchRemindMessage> page) {
        AuthUser user = ShiroKit.getUser();
        Assert.isFalse(Objects.isNull(user), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });
        QueryWrapper<WorkbenchRemindMessage> wrapper = new QueryWrapper<>();
        wrapper.eq("remind_id",user.getId());
        return messageMapper.selectPage(page,wrapper);
    }

    @Override
    public ReturnDTO readMessage(IdDTO idDto) {
        UpdateWrapper<WorkbenchRemindMessage> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id",idDto.getId()).set("status", 1);
        if(messageMapper.update(null, updateWrapper)>0){
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public ReturnDTO expirationReminder(IdDTO idDto) {
        MeterCertificate meterCertificate = meterCertificateMapper.selectById(idDto.getId());
        MeterStaff meterStaff = meterStaffMapper.selectById(meterCertificate.getStaffId());
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("account",meterStaff.getAccount());
        UserInfo userInfo = userInfoMapper.selectOne(wrapper);
        if(ObjectUtil.isEmpty(userInfo)){
            throw new BusinessException(BusinessExceptionEnum.NOT_FOUND_USER_INFO);
        }
        AuthUser user = ShiroKit.getUser();
        Assert.isFalse(Objects.isNull(user), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });
        WorkbenchRemindMessage remindMessage = new WorkbenchRemindMessage(userInfo.getId(),Long.parseLong(userInfo.getDeptId()),idDto.getId(),meterCertificate.getCertificateNo(), MessageTypeEnum.METER_CERTIFICATE.getCode(),MessageSourceModuleEnum.METER.getCode(),MessageTypeEnum.METER_CERTIFICATE.getValue(),MessageTypeEnum.METER_CERTIFICATE.getValue(),meterCertificate.getCertificateName(),0,user.getId(),user.getName());
        if(messageMapper.insert(remindMessage)>0){
            // 新增到消息列表后向用户推送消息
            webSocket.sendOneMessage(String.valueOf(userInfo.getId()),JSONObject.toJSONString(remindMessage));
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Autowired
    private IMessagePushService messagePushService;


    @Override
    public void regularExpirationReminder() {
        List<WorkbenchRemindMessage> messageList = new ArrayList<>();
        // 获取即将过期的证书列表(过期时间距离过期还差30天)
        List<WorkbenchRemindMessage> list = meterCertificateMapper.queryReminderList();
        if(null != list && list.size()!=0){
            List<Long> idList = new ArrayList<>();
            for (WorkbenchRemindMessage remindMessage : list) {
                idList.add(remindMessage.getBusinessId());
            }
            QueryWrapper<WorkbenchRemindMessage> wrapper = new QueryWrapper<>();
            wrapper.select("business_id");
            wrapper.in("business_id", idList);
            // 通过证书id查询消息表中已经手动发送过得消息
            List<Object> messageIds = messageMapper.selectObjs(wrapper);
            // 将证书列表通过证书id分组
            Map<Long, List<WorkbenchRemindMessage>> collect = list.parallelStream().collect(Collectors.groupingBy(WorkbenchRemindMessage::getBusinessId));
            // 移除已经发送过消息的证书信息
            messageIds.forEach(collect::remove);
            // 讲需要发送消息的证书整合
            for (Long id : collect.keySet()) {
                messageList.addAll(collect.get(id));
            }
            // 补充业务数据
            for (WorkbenchRemindMessage message : messageList) {
                message.setMessageType(MessageTypeEnum.METER_CERTIFICATE.getCode());
                message.setMessageSourceModule(MessageSourceModuleEnum.METER.getCode());
                message.setMessageTitle(MessageTypeEnum.METER_CERTIFICATE.getValue());
                message.setMessageTopic(MessageTypeEnum.METER_CERTIFICATE.getValue());
                message.setStatus(0);
                message.setCreateUser(Long.valueOf(MeterRoleTypeEnum.ADMIN.getCode()));
                message.setCreateUserName(MeterRoleTypeEnum.ADMIN.getValue());
                messagePushService.pushToUser(message);
            }
            log.info("定时任务新增消息表："+messageList);
            messageService.saveBatch(messageList);
            webSocket.sendMessage(messageList);
        }
    }
    @Override
    public ReturnDTO dataCheck(List<MeterCertificateImport> list) {
        QueryWrapper<MeterStaff> wrapper = new QueryWrapper<>();
        // 获取计量人员信息
        List<MeterStaff> meterStaffs = meterStaffMapper.selectList(wrapper);
        Map<String, List<MeterStaff>> staffMap = meterStaffs.parallelStream().collect(Collectors.groupingBy(MeterStaff::getStaffNo));
        AtomicBoolean checkResult = new AtomicBoolean(true);
        list.forEach(bean-> {
            StringBuilder result = new StringBuilder();
            // 校验数据中的人员编号是否存在
            if (null == staffMap.get(bean.getStaffNo())) {
                result.append(BusinessExceptionEnum.STAFF_NOT_EXISTENCE.getMessage());
                checkResult.set(false);
            }
            // 校验数据中的日期格式是否正确
            if(isDateFormat(bean.getValidDate())){
                result.append(BusinessExceptionEnum.VALID_DATE_NOT_CORRECT.getMessage());
                checkResult.set(false);
            }
            if(isDateFormat(bean.getCertificateDate())){
                result.append(BusinessExceptionEnum.CERTIFICATE_DATE_NOT_CORRECT.getMessage());
                checkResult.set(false);
            }
            bean.setResult(result.toString());
        });
        if(checkResult.get()){
            // 校验通过批量新增
            list.forEach(bean->{
                // 获取id
                Long id= IdWorker.getId();
                bean.setId(id);
                // 获取人员编号对应的人员id
                bean.setStaffNo(String.valueOf(staffMap.get(bean.getStaffNo()).get(0).getId()));
            });
            meterCertificateMapper.addCertificate(list);
            return ReturnUtil.success();
        }else{
            // 校验不通过
            // 将处理后的数据导出成文件
            MultipartFile[] file = ExportUtils.exportMultipartFile(list, "checkResult", MeterCertificateImport.class);
            // 将文件存储到minio中返回文件id,供前台下载
            List<String> upload = minioUtil.upload(file);
            return ReturnUtil.failed(upload.get(0));
        }
    }
    private List<MeterCertificateDto> supplementList(List<MeterCertificateDto> meterCertificateDtoList){
        String format = DateUtils.format(new Date(),"yyyy-MM-dd");
        for (MeterCertificateDto meterCertificateDto : meterCertificateDtoList) {
            meterCertificateDto.setTechnologyJob(dictService.getDictNameByCode(MeterDictEnum.TECHNOLOGY_JOB,meterCertificateDto.getTechnologyJob()));
            meterCertificateDto.setAdministrationJob(dictService.getDictNameByCode(MeterDictEnum.ADMINISTRATION_JOB,meterCertificateDto.getAdministrationJob()));
            meterCertificateDto.setEducation(dictService.getDictNameByCode(MeterDictEnum.EDUCATION,meterCertificateDto.getEducation()));
            if(null != meterCertificateDto.getValidDate() && format.compareTo(meterCertificateDto.getValidDate()) > 0) {
                //失效
                meterCertificateDto.setCertificateStatus("1");
                meterCertificateDto.setCertificateStatusName("已失效");
            }else{
                //正常
                meterCertificateDto.setCertificateStatus("0");
                meterCertificateDto.setCertificateStatusName("正常");
            }
        }
        return meterCertificateDtoList;
    }
}
