package com.yeejoin.amos.boot.module.jg.biz.edit.process.equip;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.yeejoin.amos.boot.biz.common.entity.BaseEntity;
import com.yeejoin.amos.boot.biz.common.utils.SnowflakeIdUtil;
import com.yeejoin.amos.boot.module.common.api.dao.ESEquipmentCategory;
import com.yeejoin.amos.boot.module.common.api.dto.ESEquipmentCategoryDto;
import com.yeejoin.amos.boot.module.jg.api.dto.*;
import com.yeejoin.amos.boot.module.jg.biz.edit.constant.EditConstant;
import com.yeejoin.amos.boot.module.jg.biz.edit.typeHandler.CbDataDictTypeHandler;
import com.yeejoin.amos.boot.module.jg.biz.edit.typeHandler.PieLineLevelTypeHandler;
import com.yeejoin.amos.boot.module.jg.biz.service.impl.IdxBizJgProjectContraptionServiceImpl;
import com.yeejoin.amos.boot.module.jg.biz.service.impl.IdxBizJgSupervisionInfoServiceImpl;
import com.yeejoin.amos.boot.module.jg.biz.service.impl.IdxBizJgTechParamsPipelineServiceImpl;
import com.yeejoin.amos.boot.module.jg.biz.service.impl.IdxBizJgUseInfoServiceImpl;
import com.yeejoin.amos.boot.module.ymt.api.entity.*;
import com.yeejoin.amos.boot.module.ymt.api.mapper.SuperviseInfoMapper;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Component
@RequiredArgsConstructor
@Getter
public class PieLineDataChangeServiceImpl {

    public static final String PIE_LINE_DELETE = "pie_line_delete";

    public static final String PIE_LINE_CREATE = "pie_line_create";

    public static final String PIE_LINE_KEY = "record";

    private final IdxBizJgSupervisionInfoServiceImpl supervisionInfoService;

    private final ESEquipmentCategory esEquipmentCategory;

    private final SuperviseInfoMapper superviseInfoMapper;

    private final CommonEquipDataProcessService commonEquipDataProcessService;

    private final IdxBizJgProjectContraptionServiceImpl idxBizJgProjectContraptionServiceImpl;

    private final EquipChangeDataUpdateServiceImpl equipChangeDataUpdateServiceImpl;

    private final IdxBizJgTechParamsPipelineServiceImpl idxBizJgTechParamsPipelineService;

    private final SnowflakeIdUtil idUtil;

    private final PieLineLevelTypeHandler pieLineLevelTypeHandler;

    private final CbDataDictTypeHandler cbDataDictTypeHandler;

    private final IdxBizJgUseInfoServiceImpl useInfoService;


    public void update(ProjectContraptionChangeDataDto projectContraptionChangeDataDtoNew, List<FieldChangeMeta> allChangeColumns) {
        // 原有对象行转列
        ProjectContraptionChangeDataDto projectContraptionChangeDataDtoOld = getOldProjectContraptionData(projectContraptionChangeDataDtoNew);
        List<FieldChangeMeta> newProjectContraptionChangeData = commonEquipDataProcessService.convertBeanField2Column2(projectContraptionChangeDataDtoNew, projectContraptionChangeDataDtoNew.getProjectContraptionId());
        // 新对象构造行转列
        List<FieldChangeMeta> oldProjectContraptionChangeData = commonEquipDataProcessService.convertBeanField2Column2(projectContraptionChangeDataDtoOld, projectContraptionChangeDataDtoNew.getProjectContraptionId());
        // 数据比对记录变化字段列表
        allChangeColumns.addAll(commonEquipDataProcessService.mergeChangeFields(newProjectContraptionChangeData, oldProjectContraptionChangeData));
        // 数据入库
        LambdaUpdateWrapper<IdxBizJgProjectContraption> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(IdxBizJgProjectContraption::getCity, projectContraptionChangeDataDtoNew.getCity());
        updateWrapper.set(IdxBizJgProjectContraption::getCityName, projectContraptionChangeDataDtoNew.getCityName());
        updateWrapper.set(IdxBizJgProjectContraption::getCounty, projectContraptionChangeDataDtoNew.getCounty());
        updateWrapper.set(IdxBizJgProjectContraption::getCountyName, projectContraptionChangeDataDtoNew.getCountyName());
        updateWrapper.set(IdxBizJgProjectContraption::getStreet, projectContraptionChangeDataDtoNew.getStreet());
        updateWrapper.set(IdxBizJgProjectContraption::getStreetName, projectContraptionChangeDataDtoNew.getStreetName());
        updateWrapper.set(IdxBizJgProjectContraption::getAddress, projectContraptionChangeDataDtoNew.getAddress());
        updateWrapper.set(IdxBizJgProjectContraption::getStartLatitudeLongitude, projectContraptionChangeDataDtoNew.getStartLatitudeLongitude());
        updateWrapper.set(IdxBizJgProjectContraption::getEndLatitudeLongitude, projectContraptionChangeDataDtoNew.getEndLatitudeLongitude());
        updateWrapper.set(IdxBizJgProjectContraption::getProjectContraption, projectContraptionChangeDataDtoNew.getProjectContraption());
        updateWrapper.set(IdxBizJgProjectContraption::getProjectContraptionNo, projectContraptionChangeDataDtoNew.getProjectContraptionNo());
        updateWrapper.set(IdxBizJgProjectContraption::getProductPhoto, projectContraptionChangeDataDtoNew.getProductPhoto());
        updateWrapper.set(IdxBizJgProjectContraption::getOtherAccessories, projectContraptionChangeDataDtoNew.getOtherAccessories());
        updateWrapper.set(IdxBizJgProjectContraption::getProductQualificationCertificate, projectContraptionChangeDataDtoNew.getProductQualificationCertificate());
        updateWrapper.set(BaseEntity::getRecDate, new Date());
        updateWrapper.eq(BaseEntity::getSequenceNbr, projectContraptionChangeDataDtoNew.getProjectContraptionId());
        idxBizJgProjectContraptionServiceImpl.update(null, updateWrapper);
    }

    private ProjectContraptionChangeDataDto getOldProjectContraptionData(ProjectContraptionChangeDataDto projectContraptionChangeDataDtoNew) {
        IdxBizJgProjectContraption projectContraption = idxBizJgProjectContraptionServiceImpl.getById(projectContraptionChangeDataDtoNew.getProjectContraptionId());
        return BeanUtil.copyProperties(projectContraption, ProjectContraptionChangeDataDto.class);
    }

    public void saveDesignForPieLine(String record, List<FieldChangeMeta> allChangeColumns, PipelineChangeItemDto pipelineChangeItemDto) {
        // 1.记录变化的数据对象
        PieLineDesignChangeDataDto pieLineDesignChangeDataDto = BeanUtil.copyProperties(pipelineChangeItemDto, PieLineDesignChangeDataDto.class);
        // 构造新对象行转列
        List<FieldChangeMeta> designInfoNew = commonEquipDataProcessService.convertBeanField2Column2(pieLineDesignChangeDataDto, record);
        // 老数据查询行转列
        List<FieldChangeMeta> designInfoOld = commonEquipDataProcessService.buildDesignInfoOld(record);
        allChangeColumns.addAll(commonEquipDataProcessService.mergeChangeFields(designInfoNew, designInfoOld));
        // 2.更新管道的设计单位名称
        equipChangeDataUpdateServiceImpl.updatePieLineDesignData(record, pieLineDesignChangeDataDto);
    }

    public void updateEs(ProjectContraptionChangeDataDto projectContraptionChangeDataDto) {
        equipChangeDataUpdateServiceImpl.updateRegisterEsDataPieLine(projectContraptionChangeDataDto);
    }

    public void deletePieLineBatch(List<PipelineChangeItemDto> deletedPieLines, List<FieldChangeMeta> allChangeColumns, String projectContraptionId) {
        List<String> recordsForDeleted = deletedPieLines.stream().map(TechParamsPipelineChangeFieldDto::getRecord).collect(Collectors.toList());
        // 构建删除日志
        this.buildDeletePieLineLog(deletedPieLines, allChangeColumns, projectContraptionId);
        // 删除涉及的19张表的数据
        superviseInfoMapper.deleteDataAll(recordsForDeleted);
        List<ESEquipmentCategoryDto> esDtoList = recordsForDeleted.stream().map(v -> {
            ESEquipmentCategoryDto esDto = new ESEquipmentCategoryDto();
            esDto.setSEQUENCE_NBR(v);
            return esDto;
        }).collect(Collectors.toList());
        // 删除es中的数据
        esEquipmentCategory.deleteAll(esDtoList);
    }

    private void buildDeletePieLineLog(List<PipelineChangeItemDto> recordsForDeleted, List<FieldChangeMeta> allChangeColumns, String projectContraptionId) {
        recordsForDeleted.forEach(item -> {
            FieldChangeMeta fieldChangeMeta = new FieldChangeMeta();
            fieldChangeMeta.setChangeId(projectContraptionId);
            fieldChangeMeta.setColumnKey(PIE_LINE_KEY);
            fieldChangeMeta.setChangeId(projectContraptionId + "/" + item.getRecord());
            fieldChangeMeta.setColumnLabel("管道删除");
            fieldChangeMeta.setColumnType("String");
            fieldChangeMeta.setFieldDisplayDefine(null);
            fieldChangeMeta.setColumnFamily(PIE_LINE_DELETE);
            fieldChangeMeta.setIsRepeatColumn(false);
            fieldChangeMeta.setColumnOldValue(item.getRecord());
            fieldChangeMeta.setDisplayOldValue(item.getPipelineNumber());
            fieldChangeMeta.setColumnNewValue(null);
            fieldChangeMeta.setDisplayNewValue(null);
            allChangeColumns.add(fieldChangeMeta);
        });
    }

    void newPieLine(ProjectContraptionChangeDataDto projectContraptionChangeDataDto, PipelineChangeItemDto newPieLine, List<FieldChangeMeta> allChangeColumns) {
        String record = idUtil.nextId().toString();
        newPieLine.setRecord(record);
        newPieLine.setProjectContraptionId(projectContraptionChangeDataDto.getProjectContraptionId());
        this.buildNewPieLineLog(projectContraptionChangeDataDto, record, allChangeColumns, newPieLine);
        // 检验信息
        IdxBizJgInspectionDetectionInfo inspectionDetectionInfo = BeanUtil.copyProperties(newPieLine, IdxBizJgInspectionDetectionInfo.class);
        if (!ValidationUtil.isEmpty(inspectionDetectionInfo)) {
            inspectionDetectionInfo.setRecord(record);
            inspectionDetectionInfo.setRecDate(new Date());
            inspectionDetectionInfo.setSequenceNbr(null);
            if (inspectionDetectionInfo.getNextInspectDate() != null) {
                inspectionDetectionInfo.setNextInspectDate(DateUtil.parse(DateUtil.format(inspectionDetectionInfo.getNextInspectDate(), DatePattern.NORM_DATE_PATTERN)));
            }
            commonEquipDataProcessService.getJgUseRegistrationService().getInspectionDetectionInfoService().getBaseMapper().insert(inspectionDetectionInfo);
            newPieLine.setJySeq(inspectionDetectionInfo.getSequenceNbr());
        }

        // 使用信息
        IdxBizJgUseInfo useInfo = BeanUtil.copyProperties(newPieLine, IdxBizJgUseInfo.class);
        useInfo.setRecord(record);
        useInfo.setSequenceNbr(null);
        useInfo.setRecDate(new Date());
        // 汇总表打印会使用
        useInfo.setUseDate(projectContraptionChangeDataDto.getUseDate());
        useInfo.setDataSource(projectContraptionChangeDataDto.getDataSource());
        useInfo.setIsIntoManagement(Boolean.FALSE);
        SingleProjectEquipChangeProcess.setNewUseAddressInfo(projectContraptionChangeDataDto, useInfo);
        commonEquipDataProcessService.getIdxBizJgUseInfoService().save(useInfo);

        // 设计信息
        IdxBizJgDesignInfo designInfo = BeanUtil.copyProperties(newPieLine, IdxBizJgDesignInfo.class);
        designInfo.setRecord(record);
        designInfo.setRecDate(new Date());
        designInfo.setSequenceNbr(null);
        commonEquipDataProcessService.getIdxBizJgDesignInfoMapper().insert(designInfo);

        // 制造信息
        IdxBizJgFactoryInfo factoryInfo = BeanUtil.copyProperties(newPieLine, IdxBizJgFactoryInfo.class);
        factoryInfo.setRecord(record);
        factoryInfo.setRecDate(new Date());
        factoryInfo.setSequenceNbr(null);
        commonEquipDataProcessService.getJgFactoryInfoMapper().insert(factoryInfo);

        // 施工信息
        newPieLine.setUscDate(newPieLine.getUscDate() != null ? DateUtil.parse(newPieLine.getUscDate(), DatePattern.NORM_MONTH_FORMAT).toDateStr() : null);
        IdxBizJgConstructionInfo constructionInfo = BeanUtil.copyProperties(newPieLine, IdxBizJgConstructionInfo.class);
        constructionInfo.setRecord(record);
        constructionInfo.setRecDate(new Date());
        constructionInfo.setUscUnitCreditCode(projectContraptionChangeDataDto.getUscUnitCreditCode());
        constructionInfo.setUscUnitName(projectContraptionChangeDataDto.getUscUnitName());
        constructionInfo.setSequenceNbr(null);
        commonEquipDataProcessService.getJgConstructionInfoService().save(constructionInfo);

        // 注册登记信息
        IdxBizJgRegisterInfo registerInfo = BeanUtil.copyProperties(newPieLine, IdxBizJgRegisterInfo.class);
        registerInfo.setRecord(record);
        registerInfo.setRecDate(new Date());
        registerInfo.setSequenceNbr(null);
        registerInfo.setEquCodeType("2");
        registerInfo.setRegisterState(this.getRegCode());
        registerInfo.setEquList(projectContraptionChangeDataDto.getEquList());
        registerInfo.setEquCategory(projectContraptionChangeDataDto.getEquCategory());
        registerInfo.setEquDefine(projectContraptionChangeDataDto.getEquDefine());
        // 补丁：saveOrUpdate在update数据时不会更新字段为null的字段，但是编辑设备的代码时，从有改成无，equCode解析成null，但是此时需要将equcode删掉
        registerInfo.setEquCode(ObjectUtils.isEmpty(registerInfo.getEquCode()) ? "" : registerInfo.getEquCode());

        // 监督管理
        IdxBizJgSupervisionInfo supervisionInfo = BeanUtil.copyProperties(newPieLine, IdxBizJgSupervisionInfo.class);
        supervisionInfo.setRecord(record);
        supervisionInfo.setRecDate(new Date());
        supervisionInfo.setSequenceNbr(null);
        supervisionInfoService.save(supervisionInfo);

        // 其他信息
        IdxBizJgOtherInfo otherInfo = BeanUtil.copyProperties(newPieLine, IdxBizJgOtherInfo.class);
        otherInfo.setRecord(record);
        otherInfo.setSequenceNbr(null);
        otherInfo.setClaimStatus("已认领");
        otherInfo.setRecDate(new Date());
        commonEquipDataProcessService.getIdxBizJgOtherInfoMapper().insert(otherInfo);

        //管道技术参数
        IdxBizJgTechParamsPipeline pipelineInfo = BeanUtil.copyProperties(newPieLine, IdxBizJgTechParamsPipeline.class);
        if (!ValidationUtil.isEmpty(pipelineInfo)) {
            pipelineInfo.setRecord(record);
            pipelineInfo.setRecDate(new Date());
            pipelineInfo.setSequenceNbr(null);
        }
        idxBizJgTechParamsPipelineService.save(pipelineInfo);
        registerInfo.setProductName(pipelineInfo.getPipeName());
        commonEquipDataProcessService.getJgRegisterInfoService().save(registerInfo);

        ESEquipmentCategoryDto esEquipmentDto = BeanUtil.copyProperties(newPieLine, ESEquipmentCategoryDto.class);
        esEquipmentDto.setDATA_SOURCE(useInfo.getDataSource());
        if (inspectionDetectionInfo.getNextInspectDate() != null) {
            esEquipmentDto.setNEXT_INSPECT_DATE(inspectionDetectionInfo.getNextInspectDate().getTime());
        }
        esEquipmentDto.setREC_DATE(new Date().getTime());
        esEquipmentDto.setSEQUENCE_NBR(record);
        esEquipmentDto.setIS_INTO_MANAGEMENT(false);
        esEquipmentDto.setEQU_CATEGORY_CODE(projectContraptionChangeDataDto.getEquCategory());
        esEquipmentDto.setEQU_CATEGORY(projectContraptionChangeDataDto.getEquCategoryName());
        esEquipmentDto.setEQU_LIST_CODE(projectContraptionChangeDataDto.getEquList());
        esEquipmentDto.setEQU_LIST(projectContraptionChangeDataDto.getEquListName());
        esEquipmentDto.setEQU_DEFINE_CODE(projectContraptionChangeDataDto.getEquDefine());
        esEquipmentDto.setEQU_DEFINE(projectContraptionChangeDataDto.getEquDefineName());
        esEquipmentDto.setSTATUS("已认领");
        esEquipmentDto.setIS_INTO_MANAGEMENT(false);
        esEquipmentDto.setUSC_UNIT_CREDIT_CODE(projectContraptionChangeDataDto.getUscUnitCreditCode());
        esEquipmentDto.setUSC_UNIT_NAME(projectContraptionChangeDataDto.getUscUnitName());
        esEquipmentDto.setUSE_UNIT_CREDIT_CODE(projectContraptionChangeDataDto.getUseUnitCreditCode());
        esEquipmentDto.setUSE_UNIT_NAME(projectContraptionChangeDataDto.getUseUnitName());
        esEquipmentDto.setPROJECT_CONTRAPTION(projectContraptionChangeDataDto.getProjectContraption());
        esEquipmentDto.setPRODUCT_NAME(pipelineInfo.getPipeName());
        esEquipmentDto.setProjectContraptionId(projectContraptionChangeDataDto.getProjectContraptionId());
        if (inspectionDetectionInfo.getNextInspectDate() != null) {
            esEquipmentDto.setNEXT_INSPECT_DATE(inspectionDetectionInfo.getNextInspectDate().getTime());
        }
        esEquipmentCategory.save(esEquipmentDto);
    }

    private void buildNewPieLineLog(ProjectContraptionChangeDataDto projectContraptionChangeDataDto, String record, List<FieldChangeMeta> allChangeColumns, PipelineChangeItemDto newPieLine) {
        FieldChangeMeta fieldChangeMeta = new FieldChangeMeta();
        fieldChangeMeta.setChangeId(projectContraptionChangeDataDto.getProjectContraptionId());
        fieldChangeMeta.setColumnKey(PIE_LINE_KEY);
        fieldChangeMeta.setColumnLabel("管道新增");
        fieldChangeMeta.setColumnType("String");
        fieldChangeMeta.setChangeId(projectContraptionChangeDataDto.getProjectContraptionId() + "/" + record);
        fieldChangeMeta.setFieldDisplayDefine(null);
        fieldChangeMeta.setColumnFamily(PIE_LINE_CREATE);
        fieldChangeMeta.setIsRepeatColumn(false);
        fieldChangeMeta.setDisplayNewValue(record);
        fieldChangeMeta.setColumnOldValue(null);
        fieldChangeMeta.setDisplayOldValue(null);
        fieldChangeMeta.setColumnNewValue(record);
        fieldChangeMeta.setDisplayNewValue(newPieLine.getPipelineNumber());
        allChangeColumns.add(fieldChangeMeta);
    }

    private String getRegCode() {
        return commonEquipDataProcessService.getJgRegisterInfoService().getRegCode();
    }

    public List<Map<String, Object>> buildEquipmentLists(Map<String, List<PipelineChangeItemDto>> pipelineChangeItemMap) {
        List<PipelineChangeItemDto> newPipelines = pipelineChangeItemMap.get(EditConstant.NEW_PIPELINES);
        List<PipelineChangeItemDto> updPipelines = pipelineChangeItemMap.get(EditConstant.UPDATE_PIPELINES);
        // 兼容处理使用登记，管道级别存的为name,标准编辑为code,管道名称（登记单元）key为productName，而非为标准的pipeName
        return Stream.concat(newPipelines.stream(), updPipelines.stream()).map(item -> {
            Map<String, Object> one = BeanUtil.beanToMap(item);
            // 管道级别存的为name,标准编辑为code,进行转换，code时返回name, name时返回还是name
            one.put("deviceLevel", pieLineLevelTypeHandler.handle(item.getDeviceLevel()));
            one.put("productName", item.getPipeName());
            // 日期字段处理
            one.put("inspectDate", DateUtil.formatDate(item.getInspectDate()));
            one.put("nextInspectDate", DateUtil.formatDate(item.getNextInspectDate()));
            // 检验结论名称
            one.put("inspectConclusion", cbDataDictTypeHandler.handle("JYJL", item.getInspectConclusionCode()));
            // json需要处理 否则JSON.toJSONString 回转义
            one.put("inspectReport", JSON.parse(item.getInspectReport()));
            return one;
        }).collect(Collectors.toList());
    }

    public void updatePipelineLength(String projectContraptionId) {
        LambdaUpdateWrapper<IdxBizJgProjectContraption> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(BaseEntity::getSequenceNbr, projectContraptionId);
        wrapper.set(IdxBizJgProjectContraption::getPipelineLength, this.calTotalPieLineLength(projectContraptionId));
        idxBizJgProjectContraptionServiceImpl.update(wrapper);

    }

    private Double calTotalPieLineLength(String projectContraptionId) {
        List<String> records = useInfoService.list(new LambdaQueryWrapper<IdxBizJgUseInfo>().eq(IdxBizJgUseInfo::getProjectContraptionId, projectContraptionId).select(IdxBizJgUseInfo::getRecord)).stream().map(IdxBizJgUseInfo::getRecord).collect(Collectors.toList());
        List<IdxBizJgTechParamsPipeline> techParamsPipelines = idxBizJgTechParamsPipelineService.list(new LambdaQueryWrapper<IdxBizJgTechParamsPipeline>().in(IdxBizJgTechParamsPipeline::getRecord, records).select(IdxBizJgTechParamsPipeline::getRecord, IdxBizJgTechParamsPipeline::getPipeLength));
        return techParamsPipelines.stream().filter(i -> i.getPipeLength() != null).map(e -> new BigDecimal(e.getPipeLength()))
                .reduce(BigDecimal.ZERO, BigDecimal::add)
                .setScale(3, RoundingMode.HALF_UP).doubleValue();
    }

    public String calPipelineLength(Map<String, List<PipelineChangeItemDto>> pipelineChangeItemMap) {
        List<PipelineChangeItemDto> newPipelines = pipelineChangeItemMap.get(EditConstant.NEW_PIPELINES);
        List<PipelineChangeItemDto> updPipelines = pipelineChangeItemMap.get(EditConstant.UPDATE_PIPELINES);
        return Stream.concat(newPipelines.stream(), updPipelines.stream()).filter(i -> i.getPipeLength() != null).map(e -> new BigDecimal(String.valueOf(e.getPipeLength()))).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(3, RoundingMode.HALF_UP).toPlainString();
    }

}
