package com.yeejoin.amos.api.openapi.face.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.google.common.collect.Lists;
import com.yeejoin.amos.api.openapi.face.model.*;
import com.yeejoin.amos.api.openapi.face.orm.dao.ESCylinderFillingRecordRepository;
import com.yeejoin.amos.api.openapi.face.orm.dao.ESCylinderInfoRepository;
import com.yeejoin.amos.api.openapi.face.orm.dao.MidEquipRegistrationInfoMapper;
import com.yeejoin.amos.boot.biz.common.utils.DateUtils;
import com.yeejoin.amos.boot.biz.common.utils.SnowflakeIdUtil;
import com.yeejoin.amos.boot.module.cylinder.api.entity.ESCylinderFillingRecordDto;
import com.yeejoin.amos.boot.module.cylinder.api.entity.ESCylinderInfoDto;
import com.yeejoin.amos.boot.module.cylinder.api.enums.CylDictEnum;
import com.yeejoin.amos.boot.module.cylinder.flc.api.entity.*;
import com.yeejoin.amos.boot.module.cylinder.flc.api.mapper.*;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StopWatch;
import org.typroject.tyboot.component.emq.EmqKeeper;
import org.typroject.tyboot.core.foundation.utils.Bean;

import java.text.ParseException;
import java.util.*;

@Slf4j
@Component
@DS("tzs")
public class SyncCylinderDataService {
    /**
     * 气瓶企业信息
     */
    @Autowired
    private CylinderUnitMapper cylinderUnitMapper;
    /**
     * 气瓶基本信息
     */
    @Autowired
    private CylinderInfoMapper cylinderInfoMapper;
    /**
     * 液化气体气瓶充装信息-充装后复查
     */
    @Autowired
    private CylinderFillingCheckMapper cylinderFillingCheckMapper;
    @Autowired
    private CylCylinderFillingCheckMapper cylCylinderFillingCheckMapper;
    /**
     * 液化气体气瓶充装信息审核
     */
    @Autowired
    private CylinderFillingExamineMapper cylinderFillingExamineMapper;
    /**
     * 气瓶标签信息
     */
    @Autowired
    private CylinderTagsMapper cylinderTagsMapper;
    /**
     * 气瓶检验信息
     */
    @Autowired
    private CylinderInspectionMapper cylinderInspectionMapper;

    @Autowired
    CylinderFillingRecordMapper cylinderFillingRecordMapper;

    @Autowired
    ESCylinderFillingRecordRepository esCylinderFillingRecordRepository;

    @Autowired
    ESCylinderInfoRepository esCylinderInfoRepository;

    @Autowired
    EmqKeeper emqKeeper;

    @Autowired
    TmCylinderInfoService tmCylinderInfoService;

    @Autowired
    CylinderOffloadingMapper cylinderOffloadingMapper;

    @Autowired
    MidEquipRegistrationInfoMapper registrationInfoMapper;

    @Autowired
    private SnowflakeIdUtil sequence;

    @Value("${cylinder.filling.insert.topic:cylinder/filling/insert/topic}")
    private String insertTopic;

    public void syncCylinderUnit(List<TmCylinderUnitModel> cylinderUnitDto) {
        List<CylinderUnit> cylinderUnitList = Bean.toModels(cylinderUnitDto, CylinderUnit.class);
        cylinderUnitMapper.saveOrUpdateBatch(cylinderUnitList);
    }

    public void syncCylinderInfo(final List<TmCylinderInfoModel> cylinderInfoDto) {
        List<CylinderInfo> cylinderUnitList = Bean.toModels(cylinderInfoDto, CylinderInfo.class);
        // 处理字典值
        cylinderUnitList.forEach(cylinderInfo -> {
            cylinderInfo.setCylinderStatus(Objects.requireNonNull(CylDictEnum.getEnum(cylinderInfo.getCylinderStatus(),
                    CylDictEnum.cylinder_Status_0.getKey())).getSeqNbr());
            cylinderInfo.setCylinderVariety(Objects.requireNonNull(CylDictEnum.getEnum(cylinderInfo.getCylinderVariety(),
                    CylDictEnum.cylinder_Variety_1.getKey())).getSeqNbr());
        });
        cylinderInfoMapper.saveOrUpdateBatch(cylinderUnitList);
    }

    public void syncCylinderFillingExamine(List<TmCylinderFillingExamineModel> cylinderFillingExamineDto) {
        List<CylinderFillingExamine> cylinderFillingExamineList = Bean.toModels(cylinderFillingExamineDto,
                CylinderFillingExamine.class);
        cylinderFillingExamineMapper.saveOrUpdateBatch(cylinderFillingExamineList);
    }

    public void syncCylinderFillingRecord(List<TmCylinderFillingRecordModel> cylinderFillingRecordDtos) {
        List<CylinderFillingRecord> cylinderFillingRecordList = Bean.toModels(cylinderFillingRecordDtos, CylinderFillingRecord.class);
        cylinderFillingRecordList.forEach(cylinderFillingRecord -> {
            cylinderFillingRecord.setAbnormal(Objects.requireNonNull(CylDictEnum.getEnum(cylinderFillingRecord.getAbnormal(), CylDictEnum.abnormal_0.getKey())).getSeqNbr());
        });
        cylCylinderFillingCheckMapper.batchInsertOrUpdate(cylinderFillingRecordList);
    }

    public void syncCylinderInspection(List<TmCylinderInspectionModel> cylinderInspectionDto) {
        List<CylinderInspection> cylinderInspectionList = Bean.toModels(cylinderInspectionDto, CylinderInspection.class);
        cylinderInspectionList.forEach(cylinderInspection -> {
            cylinderInspection.setInspectionResult(Objects.requireNonNull(CylDictEnum.getEnum(Integer.valueOf(cylinderInspection.getInspectionResult()),
                    CylDictEnum.inspection_Result_0.getKey())).getSeqNbr().toString());
        });
        cylinderInspectionMapper.saveOrUpdateBatch(cylinderInspectionList);
    }

    public void syncCylinderTag(List<TmCylinderTagsModel> cylinderTagsDtos) {
        List<CylinderTags> cylinderTagsList = Bean.toModels(cylinderTagsDtos, CylinderTags.class);
        cylinderTagsMapper.saveOrUpdateBatch(cylinderTagsList);
    }

    public void syncCylinderFillingBefore(List<TmCylinderFillingModel> cylinderFillingDtos) {
        List<CylinderFilling> cylinderFillingList = Bean.toModels(cylinderFillingDtos, CylinderFilling.class);
        cylinderFillingList.forEach(cylinderFilling -> {
            cylinderFilling.setIsValid(String.valueOf(Objects.requireNonNull(CylDictEnum.getEnum(Integer.valueOf(cylinderFilling.getIsValid()), CylDictEnum.isValid_0.getKey()))));
            cylinderFilling.setSame(Objects.requireNonNull(CylDictEnum.getEnum(cylinderFilling.getSame(),
                    CylDictEnum.same_0.getKey())).getSeqNbr());
            cylinderFilling.setIsRegulations(Objects.requireNonNull(CylDictEnum.getEnum(cylinderFilling.getIsRegulations(),
                    CylDictEnum.isRegulations_0.getKey())).getSeqNbr());
            cylinderFilling.setIsComplianceWithgbt(Objects.requireNonNull(CylDictEnum.getEnum(cylinderFilling.getIsComplianceWithgbt(),
                    CylDictEnum.isComplianceWithGBT_0.getKey())).getSeqNbr());
            cylinderFilling.setHaveStillPressure(Objects.requireNonNull(CylDictEnum.getEnum(cylinderFilling.getHaveStillPressure(),
                    CylDictEnum.haveStillPressure_0.getKey())).getSeqNbr());
            cylinderFilling.setIsComplete(Objects.requireNonNull(CylDictEnum.getEnum(cylinderFilling.getIsComplete(),
                    CylDictEnum.isComplete_0.getKey())).getSeqNbr());
            cylinderFilling.setHaveSecurityDocuments(Objects.requireNonNull(CylDictEnum.getEnum(cylinderFilling.getHaveSecurityDocuments(),
                    CylDictEnum.SecurityDocuments_0.getKey())).getSeqNbr());
        });
        cylCylinderFillingCheckMapper.saveAndBatchInsert(cylinderFillingList);
    }

    public void syncCylinderFillingAfter(List<TmCylinderFillingCheckModel> cylinderFillingCheckDtos) {
        List<CylinderFillingCheck> cylinderFillingChecList = Bean.toModels(cylinderFillingCheckDtos, CylinderFillingCheck.class);
        cylinderFillingChecList.forEach(cylinderFillingCheck -> {
            cylinderFillingCheck.setAbnormalTemperature(Objects.requireNonNull(CylDictEnum.getEnum(cylinderFillingCheck.getAbnormalTemperature(),
                    CylDictEnum.abnormalTemperature_0.getKey())).getSeqNbr());
            cylinderFillingCheck.setSealedState(Objects.requireNonNull(CylDictEnum.getEnum(cylinderFillingCheck.getSealedState(),
                    CylDictEnum.sealedState_0.getKey())).getSeqNbr());
            cylinderFillingCheck.setWarningSign(Objects.requireNonNull(CylDictEnum.getEnum(cylinderFillingCheck.getWarningSign(),
                    CylDictEnum.warningSign_0.getKey())).getSeqNbr());
            cylinderFillingCheck.setDefective(Objects.requireNonNull(CylDictEnum.getEnum(cylinderFillingCheck.getDefective(),
                    CylDictEnum.defective_0.getKey())).getSeqNbr());
            cylinderFillingCheck.setWithinScope(Objects.requireNonNull(CylDictEnum.getEnum(cylinderFillingCheck.getWithinScope(),
                    CylDictEnum.withinScope_0.getKey())).getSeqNbr());
        });
        cylinderFillingCheckMapper.saveOrUpdateByCondition(cylinderFillingChecList);
    }


    @DS("tzs")
    public void createCylinderFillingRecord(List<ESCylinderFillingRecordDto> cylinderFillingRecord) {
        if (!ObjectUtils.isEmpty(cylinderFillingRecord)) {
            // List<String> appIds = cylinderFillingRecord.stream().map(ESCylinderFillingRecordDto::getAppId).collect(Collectors.toList());
            // List<String> sequenceCodeS = cylinderFillingRecord.stream().map(ESCylinderFillingRecordDto::getSequenceCode).collect(Collectors.toList());
            // List<ESCylinderFillingRecordDto> cylinderFillingRecordInfo = cylinderFillingRecordMapper.getCylinderFillingRecordInfo(appIds, sequenceCodeS);
            // cylinderFillingRecord.stream().map(item -> {
            //     List<ESCylinderFillingRecordDto> collect = cylinderFillingRecordInfo.stream().filter(e -> item.getAppIdAndSequenceCode().equals(e.getAppIdAndSequenceCode())).collect(Collectors.toList());
            //     if (!ObjectUtils.isEmpty(collect)) {
            //         item.setSequenceNbr(collect.get(0).getSequenceNbr());
            //         item.setUnitName(collect.get(0).getUnitName());
            //         item.setFactoryNum(collect.get(0).getFactoryNum());
            //         item.setCylinderVariety(collect.get(0).getCylinderVariety());
            //         item.setCylinderVarietyName(collect.get(0).getCylinderVarietyName());
            //         item.setUnitInnerCode(collect.get(0).getUnitInnerCode());
            //         item.setSequenceCode(collect.get(0).getSequenceCode());
            //         item.setQrCode(collect.get(0).getQrCode());
            //         item.setElectronicLabelCode(collect.get(0).getElectronicLabelCode());
            //         item.setAppId(collect.get(0).getAppId());
            //         item.setCreditCode(collect.get(0).getCreditCode());
            //         item.setRegionCode(collect.get(0).getRegionCode());
            //         try {
            //             item.setInspectionDateMs(ObjectUtils.isEmpty(item.getFillingStartTime()) ? 0L : DateUtils.dateParseWithPattern(item.getFillingStartTime()).getTime());
            //             item.setInspectionDateAfterMS(ObjectUtils.isEmpty(item.getFillingEndTime()) ? 0L : DateUtils.dateParseWithPattern(item.getFillingEndTime()).getTime());
            //         } catch (ParseException e) {
            //             throw new RuntimeException(e);
            //         }
            //     }
            //     return item;
            // });
            cylinderFillingRecord.forEach(item -> {
                String sequenceCode = item.getSequenceCode();
                System.out.println("Processing sequenceCode: " + sequenceCode);

                Map<String, Object> cylUseInfo = registrationInfoMapper.getCylUseInfoBySeqCode(sequenceCode);

                if (ObjectUtils.isEmpty(cylUseInfo)) {
                    return;
                }
                item.setSequenceNbr(sequence.nextId());
                item.setUnitName(Optional.ofNullable((String) cylUseInfo.get("unitName"))
                                .orElse((String) cylUseInfo.get("fillingUnitName"))
                );
                item.setFillingUnitName(Objects.toString(cylUseInfo.get("fillingUnitName"), ""));
                item.setFactoryNum((String) cylUseInfo.get("factoryNum"));
                item.setCylinderVariety(Integer.valueOf((String) cylUseInfo.get("cylinderVariety")));
                item.setCylinderVarietyName((String) cylUseInfo.get("cylinderVarietyName"));
                item.setUnitInnerCode((String) cylUseInfo.get("unitInnerCode"));
                item.setSequenceCode((String) cylUseInfo.get("sequenceCode"));
                item.setQrCode((String) cylUseInfo.get("informationManageCode"));
                item.setElectronicLabelCode((String) cylUseInfo.get("informationManageCode"));
                item.setAppId((String) cylUseInfo.get("appId"));
                item.setCreditCode((String) cylUseInfo.get("creditCode"));
                item.setRegionCode((String) cylUseInfo.get("regionCode"));
                item.setOrgBranchCode(Objects.toString(cylUseInfo.get("orgBranchCode"),""));

                try {
                    item.setInspectionDateMs(parseDateOrDefault(item.getFillingStartTime()));
                    item.setInspectionDateAfterMS(parseDateOrDefault(item.getFillingEndTime()));
                } catch (ParseException e) {
                    item.setInspectionDateMs(0L);
                    item.setInspectionDateAfterMS(0L);
                }
            });
            saveCylinderFillingRecord2ES(cylinderFillingRecord);
        }
    }

    private long parseDateOrDefault(String date) throws ParseException {
        return ObjectUtils.isEmpty(date) ? 0L : DateUtils.dateParseWithPattern(date).getTime();
    }

    public void saveCylinderFillingRecord2ES(List<ESCylinderFillingRecordDto> records) {
        List<String> ids = new ArrayList<>();
        for (ESCylinderFillingRecordDto record : records) {
            CylinderFillingRecord cylinderFillingRecord = new CylinderFillingRecord();
            BeanUtils.copyProperties(record, cylinderFillingRecord);
            ids.add(String.valueOf(record.getSequenceNbr()));
        }
        esCylinderFillingRecordRepository.saveAll(records);
        cylinderFillingRecordMapper.updateCylinderFillingToEsStatus(ids);
        this.publishMsg2CyService(records);

    }

    /**
     * 发布记录创建消息
     *
     * @param records 所有的记录
     */
    private void publishMsg2CyService(List<ESCylinderFillingRecordDto> records) {
        try {
            log.info("开始发送气瓶充装记录数据消息:{}", JSON.toJSONString(records));
            emqKeeper.getMqttClient().publish(insertTopic, JSON.toJSONString(records).getBytes(), 2, false);
        } catch (MqttException e) {
            log.error("发送气瓶充装记录数据消息失败:{}", e.getMessage());
        }
    }

    /**
     * 同步气瓶信息至业务es
     * @param cylinderInfoModel
     */
    public void createCylinderInfo2ES(List<TmCylinderInfoModel> cylinderInfoModel) {
        List<String> seqCodeList = Lists.newArrayList();
        String appId = tmCylinderInfoService.getAppId();
        List<ESCylinderInfoDto> esCylinderInfoDtoList = Bean.toModels(cylinderInfoModel, ESCylinderInfoDto.class);
        esCylinderInfoDtoList.forEach(es -> {
            try {
                es.setInspectionDateMs(ObjectUtils.isEmpty(es.getInspectionDate()) ? 0L : DateUtils.dateParse(es.getInspectionDate(), DateUtils.DATE_TIME_PATTERN).getTime());
                seqCodeList.add(es.getSequenceCode());
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        });

        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        esCylinderInfoRepository.saveAll(esCylinderInfoDtoList);
        stopWatch.stop();
        if (log.isInfoEnabled()) {
            log.info("存入es耗时：{} 秒", stopWatch.getTotalTimeSeconds());
        }
        StopWatch stopWatch1 = new StopWatch();
        stopWatch1.start();
        cylinderInfoMapper.updateCylinderInfoEsStatusBySeqCodes(appId, seqCodeList);
        stopWatch1.stop();
        if (log.isInfoEnabled()) {
            log.info("更新业务数据耗时：{} 秒", stopWatch1.getTotalTimeSeconds());
        }
    }

    public void syncCylinderOffloading(List<TmCylinderOffloadingModel> tmCylinderOffloadingList) {
        List<CylinderOffloading> cylinderOffloadingList = Bean.toModels(tmCylinderOffloadingList, CylinderOffloading.class);
        cylinderOffloadingMapper.saveOrUpdateBatch(cylinderOffloadingList);
    }
}
