package com.cf.imes.module.system.api.systemconfig;

import cn.hutool.core.collection.CollUtil;
import com.cf.imes.framework.common.enums.CommonStatusEnum;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.util.Assert.AssertUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
import com.cf.imes.module.system.api.systemconfig.dto.ProcessSchemeDTO;
import com.cf.imes.module.system.api.systemconfig.dto.SystemConfigRespDTO;
import com.cf.imes.module.system.controller.admin.systemconfig.vo.ProcessSchemeConfig;
import com.cf.imes.module.system.dal.dataobject.lable.LabelDO;
import com.cf.imes.module.system.dal.dataobject.machine.MachineDO;
import com.cf.imes.module.system.dal.dataobject.systemconfig.SystemConfigDO;
import com.cf.imes.module.system.dal.dataobject.systemconfig.SystemConfigDataDO;
import com.cf.imes.module.system.dal.dataobject.systemconfig.SystemConfigProcessDO;
import com.cf.imes.module.system.dal.dataobject.systemconfig.SystemConfigSchemeDO;
import com.cf.imes.module.system.dal.mysql.label.LabelMapper;
import com.cf.imes.module.system.dal.mysql.machine.MachineMapper;
import com.cf.imes.module.system.dal.mysql.systemconfig.*;
import com.cf.imes.module.system.enums.config.SystemConfigTypeEnum;
import com.cf.imes.module.system.service.systemconfig.SystemConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;

import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cf.imes.framework.common.pojo.CommonResult.success;
import static com.cf.imes.framework.common.util.json.JsonUtils.parseArray;
import static com.cf.imes.framework.common.util.json.JsonUtils.unzipString;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.*;

/**
 * 系统配置feign实现类
 *
 * @author Gqr
 * @since 2024/11/15 11:39
 */
@RestController
@Validated
@Slf4j
public class SystemConfigApiImpl implements SystemConfigApi {

    @Resource
    private SystemConfigService systemConfigService;

    @Resource
    private SystemConfigMapper systemConfigMapper;

    @Resource
    private MachineMapper machineMapper;

    @Resource
    private LabelMapper labelMapper;

    @Resource
    private SystemConfigSchemeMapper systemConfigSchemeMapper;

    @Resource
    private SystemConfigProcessMapper systemConfigProcessMapper;

    @Resource
    private SystemConfigDataMapper systemConfigDataMapper;

    @Resource
    private SystemConfigSealedgeMapper systemConfigSealedgeMapper;

    @Override
    public CommonResult<SystemConfigRespDTO> getOrgCustomPlateNoConfig() {
        return success(BeanUtils.toBean(systemConfigService.getOrgCustomPlateNoConfig(), SystemConfigRespDTO.class));
    }

    @Override
    public CommonResult<SystemConfigRespDTO> getById(Long id) {
        return success(BeanUtils.toBean(systemConfigService.getSystemConfig(id,SystemConfigTypeEnum.CUSTOM_PLATE_NO.getType()), SystemConfigRespDTO.class));
    }


    @Override
    public CommonResult<List<SystemConfigRespDTO>> getProcessByIds(List<Long> processIds) {

        List<SystemConfigSchemeDO> systemConfigSchemeDOS = systemConfigSchemeMapper.selectList(new LambdaQueryWrapperX<SystemConfigSchemeDO>()
                .eq(SystemConfigSchemeDO::getOrganId, OrganContextHolder.getOrganId())
                .in(SystemConfigSchemeDO::getId, processIds)
                .select(SystemConfigSchemeDO::getId,SystemConfigDO::getName));

        if(CollUtil.isEmpty(systemConfigSchemeDOS)){
            return success(new ArrayList<>());
        }

        return success(BeanUtils.toBean(systemConfigSchemeDOS,SystemConfigRespDTO.class));
    }



    @Override
    public CommonResult<Integer> getProcessSizeByIds(List<Long> processIds) {

        List<SystemConfigSchemeDO> systemConfigSchemeDOS = systemConfigSchemeMapper.selectList(new LambdaQueryWrapperX<SystemConfigSchemeDO>()
                .eq(SystemConfigSchemeDO::getOrganId, OrganContextHolder.getOrganId())
                .in(SystemConfigSchemeDO::getId, processIds)
                .select(SystemConfigSchemeDO::getId,SystemConfigDO::getSetting));

        if(CollUtil.isEmpty(systemConfigSchemeDOS)){
            throw exception(PLAN_PROCESS_CONFIG_ALL_IS_NULL);
        }

        AtomicReference<Integer> processSize = new AtomicReference<>(0);

        systemConfigSchemeDOS.forEach(f->{

            try {

                List<ProcessSchemeConfig> processSchemeConfigs = parseArray(f.getSetting(), ProcessSchemeConfig.class);
                processSize.updateAndGet(v -> v + processSchemeConfigs.size());

            }catch (Exception e){
                log.error(e.getMessage());
                throw exception(SYSTEM_PROCESS_SCHEME_CONFIG_FIELD_ERROR);
            }

        });

        if(processSize.get() == 0){
            throw exception(PLAN_PROCESS_CONFIG_ALL_IS_NULL);
        }

        return success(processSize.get());
    }

    @Override
    public CommonResult<SystemConfigRespDTO> getDefaultProcessConfig() {

        List<SystemConfigSchemeDO> systemConfigSchemeDOS = systemConfigSchemeMapper.selectSystemConfigList(SystemConfigTypeEnum.PROCESS_SCHEME.getType(), CommonStatusEnum.ENABLE.getStatus());

        AssertUtils.notEmpty(systemConfigSchemeDOS,PROCESS_CONFIG_DEFAULT_DATA_ERROR);

        return success(BeanUtils.toBean(systemConfigSchemeDOS.get(0),SystemConfigRespDTO.class));
    }




    @Override
    public CommonResult<List<ProcessSchemeDTO>> getProcessById(Long processId) {

        SystemConfigSchemeDO systemConfigSchemeDO = systemConfigSchemeMapper.selectById(processId);

        AssertUtils.notEmpty(systemConfigSchemeDO,THIS_PROCESS_CONFIG_DATA_ERROR);

        List<ProcessSchemeConfig> processSchemeConfigs;

        try {

            processSchemeConfigs = parseArray(systemConfigSchemeDO.getSetting(), ProcessSchemeConfig.class);

        }catch (Exception e){
            log.error(e.getMessage());
            throw exception(SYSTEM_PROCESS_SCHEME_CONFIG_FIELD_ERROR);
        }

        List<ProcessSchemeDTO> schemeDTOS = BeanUtils.toBean(processSchemeConfigs, ProcessSchemeDTO.class);

        return success(getProcessSchemeConfig(schemeDTOS));

    }



    @Override
    public CommonResult<List<ProcessSchemeDTO>> getPlanProcessSchemeConfig(List<ProcessSchemeDTO> schemeDTOList) {

        return success(getProcessSchemeConfig(schemeDTOList));

    }



    @Override
    public CommonResult<List<ProcessSchemeDTO>> getProcessSchemeConfig(Long processId) {

        SystemConfigSchemeDO systemConfigSchemeDO = systemConfigSchemeMapper.selectById(processId);

        AssertUtils.notEmpty(systemConfigSchemeDO,THIS_PROCESS_CONFIG_DATA_ERROR);

        List<ProcessSchemeConfig> processSchemeConfigs;

        try {

            processSchemeConfigs = parseArray(systemConfigSchemeDO.getSetting(), ProcessSchemeConfig.class);

        } catch (Exception e) {
            log.error(e.getMessage());
            throw exception(SYSTEM_PROCESS_SCHEME_CONFIG_FIELD_ERROR);
        }

        return success(BeanUtils.toBean(processSchemeConfigs,ProcessSchemeDTO.class));

    }




    private void checkValueIsNotEmpty(List<?> value,String error) {

        if(ObjectUtils.isEmpty(value)){
            throw exception(SYSTEM_PROCESS_SCHEME_CONFIG_DATA_ERROR,error);
        }

    }




    private List<ProcessSchemeDTO> getProcessSchemeConfig(List<ProcessSchemeDTO> schemeDTOS){

        // 配置ID查询和数据校验
        List<Long> processLineConfigIds = schemeDTOS.stream().map(ProcessSchemeDTO::getProcessLineConfig).distinct().toList();

        checkValueIsNotEmpty(processLineConfigIds,"加工分线");

        List<Long> optimizationConfigIds = schemeDTOS.stream().map(ProcessSchemeDTO::getOptimizationConfig).distinct().toList();

        checkValueIsNotEmpty(optimizationConfigIds,"优化数据配置");

        List<Long> analyzerIds = schemeDTOS.stream().map(ProcessSchemeDTO::getAnalyzer).distinct().toList();

        checkValueIsNotEmpty(analyzerIds,"解析器");


        // 配置查询和数据校验
        List<SystemConfigProcessDO> processLineConfigList = systemConfigProcessMapper.selectBatchIds(processLineConfigIds);

        checkValueIsNotEmpty(processLineConfigList,"加工分线");

        List<SystemConfigDataDO> optimizationConfigList = systemConfigDataMapper.selectBatchIds(optimizationConfigIds);

        checkValueIsNotEmpty(optimizationConfigList,"优化数据配置");

        List<MachineDO> analyzerList = machineMapper.selectBatchIds(analyzerIds);

        checkValueIsNotEmpty(analyzerList,"解析器");


        // 标签ID和配置查询和数据校验
        List<Long> labelIds = analyzerList.stream().map(MachineDO::getLabelId).distinct().toList();

        AssertUtils.notEmpty(labelIds,SYSTEM_PROCESS_SCHEME_CONFIG_MACHINE_LABEL);

        List<LabelDO> labelDOS = labelMapper.selectBatchIds(labelIds);

        AssertUtils.notEmpty(labelDOS,SYSTEM_PROCESS_SCHEME_CONFIG_MACHINE_LABEL);

        // 匹配对应数据
        schemeDTOS.forEach(f->{

            f.setProcessLineConfigName(processLineConfigList.stream()
                    .filter(p->f.getProcessLineConfig().equals(p.getId()))
                    .map(SystemConfigProcessDO::getName)
                    .toList().get(0)
            );
            f.setProcessLineConfigSetting(
                    processLineConfigList.stream()
                            .filter(p->f.getProcessLineConfig().equals(p.getId()))
                            .map(SystemConfigProcessDO::getSetting)
                            .toList().get(0)
            );
            f.setProcessLineUpdateTime(
                    processLineConfigList.stream()
                            .filter(p->f.getProcessLineConfig().equals(p.getId()))
                            .map(SystemConfigProcessDO::getUpdateTime)
                            .toList().get(0)
            );

            f.setOptimizationConfigName(optimizationConfigList.stream()
                    .filter(p->f.getOptimizationConfig().equals(p.getId()))
                    .map(SystemConfigDataDO::getName)
                    .toList().get(0)
            );
            f.setOptimizationConfigSetting(
                    optimizationConfigList.stream()
                            .filter(p->f.getOptimizationConfig().equals(p.getId()))
                            .map(SystemConfigDataDO::getSetting)
                            .toList().get(0)
            );
            f.setOptimizationUpdateTime(
                    optimizationConfigList.stream()
                            .filter(p->f.getOptimizationConfig().equals(p.getId()))
                            .map(SystemConfigDataDO::getUpdateTime)
                            .toList().get(0)
            );



            MachineDO machineDO = analyzerList.stream().filter(p -> f.getAnalyzer().equals(p.getId())).toList().get(0);
            f.setAnalyzerConfigName(machineDO.getName());
            f.setAnalyzerConfigSetting(unzipString(machineDO.getSetting()));
            f.setAnalyzerUpdateTime(machineDO.getUpdateTime());
            f.setMachineType(machineDO.getMachineType());


            LabelDO labelDO = labelDOS.stream().filter(l -> machineDO.getLabelId().equals(l.getId())).toList().get(0);
            f.setLabel(labelDO.getId());
            f.setLabelHeight(labelDO.getHeight());
            f.setLabelWidth(labelDO.getWidth());
            f.setLabelType(labelDO.getType());
            f.setLabelSetting(unzipString(labelDO.getTemplate()));

        });


        return schemeDTOS;

    }




    @Override
    public CommonResult<List<SystemConfigRespDTO>> getOrgSealEdgeConfig() {
        return success(BeanUtils.toBean(systemConfigSealedgeMapper.selectSystemConfigList(SystemConfigTypeEnum.SEALEDGE.getType(), null), SystemConfigRespDTO.class));
    }
}
