package com.cf.imes.module.system.service.machine;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cf.imes.framework.common.enums.CommonStatusEnum;
import com.cf.imes.framework.common.enums.MachineTypeEnum;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.mybatis.core.query.MPJLambdaWrapperX;
import com.cf.imes.module.system.controller.admin.machine.vo.*;
import com.cf.imes.module.system.controller.admin.organ.vo.organ.OrganSimpleRespVO;
import com.cf.imes.module.system.convert.machine.MachineTemplateConvert;
import com.cf.imes.module.system.dal.dataobject.machine.MachineBrandDO;
import com.cf.imes.module.system.dal.dataobject.machinetemplate.MachineTemplateDO;
import com.cf.imes.module.system.dal.dataobject.machinetemplate.MachineTemplateLimitDO;
import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO;
import com.cf.imes.module.system.dal.mysql.machine.MachineBrandMapper;
import com.cf.imes.module.system.dal.mysql.machinetemplate.MachineTemplateLimitMapper;
import com.cf.imes.module.system.dal.mysql.machinetemplate.MachineTemplateMapper;
import com.cf.imes.module.system.dal.mysql.organ.OrganMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.cf.imes.framework.common.util.json.JsonUtils.unzipString;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.*;

/**
 * @author there
 */
@Service
@Slf4j
public class MachineTemplateServiceImpl implements MachineTemplateService {

    @Resource
    private MachineTemplateMapper machineTemplateMapper;

    @Resource
    private MachineTemplateLimitMapper machineTemplateLimitMapper;


    @Resource
    private MachineBrandMapper machineBrandMapper;

    @Resource
    private OrganMapper organMapper;

    private static final String FIELD_AUTO_LABEL_MODEL = "autoLabelModel";
    private static final String FIELD_DRILL_MODEL = "drillModel";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createCuttingTemplate(CuttingTemplateSaveReqVO reqVO) {

        // todo 测试时的判断，测试完毕后删除
        if (reqVO.getNowBrandId() == null) {
            throw new ServiceException(THE_CURRENT_BRAND);
        }

        validateMachineTemplate(reqVO.getName(), reqVO.getMachineType());


        MachineTemplateDO templateDO = MachineTemplateConvert.convert(reqVO);


        if (reqVO.getMachineId() != null) {

            MachineTemplateDO machineTemplateDO = machineTemplateMapper.selectMachine(reqVO.getBrandId(), reqVO.getMachineId());

            String updatedJsonString = handleMachineType(templateDO.getName(), machineTemplateDO.getMachineType(), machineTemplateDO.getSetting());

            templateDO.setSetting(updatedJsonString == null ? machineTemplateDO.getSetting() : JsonUtils.zipString(updatedJsonString));

            machineTemplateMapper.insert(templateDO);

            return templateDO.getId();
        }

        templateDO.setSetting(JsonUtils.zipString(templateDO.getSetting()));

        machineTemplateMapper.insert(templateDO);


        return templateDO.getId();


    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateCuttingTemplate(CuttingTemplateSaveReqVO reqVO) {

        MachineBrandDO machineBrandDO = machineBrandMapper.selectById(reqVO.getNowBrandId());
        if (machineBrandDO == null) {
            throw new ServiceException(THE_CURRENT_BRAND);
        }

        // 校验机台模板是否存在和名称是否重复
        validateMachineTemplateExists(reqVO.getName(), reqVO.getMachineType(), reqVO.getId());


        MachineTemplateDO templateDO = MachineTemplateConvert.convert(reqVO);

        if (!reqVO.getSetting().isEmpty()) {
            templateDO.setSetting(JsonUtils.zipString(templateDO.getSetting()));
        }
        machineTemplateMapper.updateById(templateDO);
        return Boolean.TRUE;
    }

    @Override
    public CuttingTemplateRespVO getCuttingTemplateById(String id) {
        MachineTemplateDO templateDO = machineTemplateMapper.selectById(id);
        if (Objects.isNull(templateDO)) {
            throw new ServiceException(MACHINE_TEMPLATE_NOT_EXISTS);
        }
        templateDO.setSetting(unzipString(templateDO.getSetting()));
        return MachineTemplateConvert.convert1(templateDO);

    }

    @Override
    public Boolean batchDeleteCuttingTemplate(MachineTemplateBrandReqVO reqVO) {

//        MachineBrandDO machineBrandDO = machineBrandMapper.selectBrand(reqVO.getBrand(),reqVO.getMachineType());

//        MachineBrandDO machineBrandDO = machineBrandMapper.selectById(reqVO.getId());

        Long brandId = reqVO.getId();
        // 校验品牌是否存在
        validateBrandExistes(brandId);

        List<MachineTemplateDO> machineTemplateDOS = machineTemplateMapper.selectByBrand(brandId);

        if (!machineTemplateDOS.isEmpty()) {
//            throw new ServiceException(MACHINE_TEMPLATE_NOT_EXISTS);

            List<Long> ids = machineTemplateDOS.stream().map(MachineTemplateDO::getId).toList();

            machineTemplateMapper.deleteBatchIds(ids);

        }


        machineBrandMapper.deleteById(brandId);
        return Boolean.TRUE;

    }


    @Override
    public Map<Integer, List<MachineTemplateRespVO>> getMachineTemplateTree() {

        List<MachineBrandDO> machineBrandDOS = machineBrandMapper.selectList();


        List<MachineTemplateRespVO> machineTemplateRespVOS = BeanUtils.toBean(machineBrandDOS, MachineTemplateRespVO.class);


        List<MachineTemplateDO> machineTemplateDOS = machineTemplateMapper.selectList()
                // 将机台的配置进行解压
                .stream()
                // todo 目前需要写上，等数据清一波后，应该不需要了
                .filter(m -> !Objects.equals(m.getBrandId(), null))
                .map(m -> m.setSetting(unzipString(m.getSetting()))).toList();

        machineTemplateRespVOS.forEach(f->
                f.setMachineTemplateDOS(machineTemplateDOS.stream()
                        .filter(m -> m.getBrandId().equals(f.getId()))
                        .toList())
        );


        return machineTemplateRespVOS.stream().collect(Collectors.groupingBy(MachineTemplateRespVO::getMachineType));


    }


    @Override
    public PageResult<OrganTemplateResp> organTemplatePage(OrganTemplatePage page) {
        Page<OrganTemplateResp> respPage = new Page<>(page.getPageNo(), page.getPageSize());


        Page<OrganTemplateResp> organTemplateRespPage = machineTemplateLimitMapper.selectMachinePage(respPage, page);

        // 分页查询出的组织信息
        List<OrganTemplateResp> organTemplateRespPageRecords = organTemplateRespPage.getRecords();

        List<Long> organIds = organTemplateRespPageRecords.stream().map(OrganTemplateResp::getOrganId).toList();


        if (organIds.isEmpty()) {
            return null;
        }

        List<MachineTemplateBrandReqVO> machineTemplateBrandReqVOS = machineTemplateLimitMapper.selectMachineList(organIds, page.getTemplateName());


        // 查询品牌名称
        List<Long> brandIds = machineTemplateBrandReqVOS.stream().map(MachineTemplateBrandReqVO::getId).toList();

        List<MachineBrandDO> machineBrandDOS = machineBrandMapper.selectBatchIds(brandIds);

        for (MachineTemplateBrandReqVO machineTemplateBrandReqVO : machineTemplateBrandReqVOS) {
            machineTemplateBrandReqVO.setBrand(machineBrandDOS.stream()
                    .filter(f -> f.getId().equals(machineTemplateBrandReqVO.getId()))
                    .map(MachineBrandDO::getBrand)
                    .findAny().orElse(null));
        }

        for (OrganTemplateResp organTemplateRespPageRecord : organTemplateRespPageRecords) {
            organTemplateRespPageRecord.setMachineTemplateBrandReqVOS(machineTemplateBrandReqVOS.stream()
                    .filter(f -> f.getOrganId().equals(organTemplateRespPageRecord.getOrganId()))
                    .toList());
        }

        return new PageResult<>(organTemplateRespPage.getRecords(), organTemplateRespPage.getTotal());

    }

    @Override
    public OrganTemplateResp organTemplateByOrganId(Long organId) {
        return machineTemplateMapper.selectOrganTemplate(organId);
    }


    @Override
    public void createMachineTemplateBrand(MachineTemplateBrandReqVO reqVO) {

        MachineBrandDO machineBrandDO = machineBrandMapper.selectBrand(reqVO.getBrand(), reqVO.getMachineType());

        if (machineBrandDO != null) {
            throw new ServiceException(THE_CURRENT_BRAND_OF_THE_MACHINE_EXISTS);
        }

        MachineBrandDO machineBrand = MachineBrandDO.builder()
                .machineType(reqVO.getMachineType())
                .brand(reqVO.getBrand())
                .build();

        machineBrandMapper.insert(machineBrand);

    }


    @Override
    public void updateMachineTemplateBrand(MachineTemplateBrandReqVO reqVO) {

//        MachineBrandDO machineBrandDO = machineBrandMapper.selectBrand(reqVO.getBrand(), reqVO.getMachineType());
        // 校验机台品牌是否存在
        MachineBrandDO machineBrandDO = validateBrandExistes(reqVO.getId());

        machineBrandDO.setBrand(reqVO.getBrand());

        machineBrandMapper.updateById(machineBrandDO);


    }


    /**
     * 校验机台品牌是否存在
     *
     * @param id
     */
    private MachineBrandDO validateBrandExistes(Long id) {
        MachineBrandDO machineBrandDO = machineBrandMapper.selectById(id);
        if (ObjectUtil.isNull(machineBrandDO)) {
            throw new ServiceException(THE_CURRENT_BRAND);
        }
        return machineBrandDO;
    }


    @Override
    public TemplateAutoResp getTemplateAuth(Long organId) {

        // todo 逻辑增强已完成，已完成如果按照组织查询，只查询当前组织下没有进行授权的机台，数据正确性待确认

        TemplateAutoResp templateAutoResp = new TemplateAutoResp();


        List<Long> machineIds;

        if (organId != null) {

            List<MachineTemplateLimitDO> machineTemplateLimitDOS = machineTemplateLimitMapper.selectListByOrganId(organId);

            machineIds = machineTemplateLimitDOS.stream().map(MachineTemplateLimitDO::getMachineId).distinct().toList();

        } else {
            machineIds = new ArrayList<>();
        }

        List<OrganizationDO> organizationDOS = organMapper.selectOrganList(CommonStatusEnum.ENABLE.getStatus());


        templateAutoResp.setOrganSimpleRespVOS(BeanUtils.toBean(organizationDOS, OrganSimpleRespVO.class));


        List<MachineBrandDO> machineBrandDOS = machineBrandMapper.selectListByType(MachineTypeEnum.CUTTING.getType());


        templateAutoResp.setMachineBrand(BeanUtils.toBean(machineBrandDOS, TemplateAutoResp.MachineBrand.class));


        List<Long> brandIds = machineBrandDOS.stream().map(MachineBrandDO::getId).toList();


        List<MachineTemplateDO> machineTemplateDoS = machineTemplateMapper
                .selectList(new MPJLambdaWrapperX<MachineTemplateDO>()
                        .in(MachineTemplateDO::getBrandId, brandIds)
                        .select(MachineTemplateDO::getId, MachineTemplateDO::getBrandId, MachineTemplateDO::getName));


        List<TemplateAutoResp.MachineTemplate> machineTemplates = BeanUtils.toBean(machineTemplateDoS, TemplateAutoResp.MachineTemplate.class);


        if (!machineIds.isEmpty()) {

            for (TemplateAutoResp.MachineBrand machineBrand : templateAutoResp.getMachineBrand()) {

                machineBrand.setMachineTemplates(machineTemplates.stream().filter(f -> f.getBrandId().equals(machineBrand.getId())).toList());


                List<TemplateAutoResp.MachineTemplate> machineTemplate = new ArrayList<>(machineBrand.getMachineTemplates().stream()

                        .filter(f -> !machineIds.contains(f.getId()))

                        .toList());


                machineBrand.setMachineTemplates(machineTemplate.stream().distinct().toList());

            }

            return templateAutoResp;

        }


        for (TemplateAutoResp.MachineBrand machineBrand : templateAutoResp.getMachineBrand()) {

            machineBrand.setMachineTemplates(machineTemplates.stream().filter(f -> f.getBrandId().equals(machineBrand.getId())).toList());

        }


        return templateAutoResp;


    }





    @Override
    public Boolean deleteCuttingTemplate(Long id) {
        MachineTemplateDO templateDO = machineTemplateMapper.selectById(id);
        if (Objects.isNull(templateDO)) {
            throw new ServiceException(MACHINE_TEMPLATE_NOT_EXISTS);
        }

        machineTemplateMapper.deleteById(id);
        return Boolean.TRUE;
    }



    @Override
    public PageResult<MachineTemplateDO> page(MachinePageReqVO pageParam) {

        PageResult<MachineTemplateDO> machineTemplateDOPageResult = machineTemplateMapper.selectPage(pageParam, new ArrayList<>());
        // 将机台模板的配置进行解压
        machineTemplateDOPageResult.setList(machineTemplateDOPageResult.getList().stream().map(m -> m.setSetting(unzipString(m.getSetting()))).collect(Collectors.toList()));

        return machineTemplateDOPageResult;
    }


    // 判断机台模板的类型
    private String handleMachineType(String machineName, Integer machineType, String machineSetting) {

        String updatedJsonString = null;

        if (machineType.equals(MachineTypeEnum.CUTTING.getType())) {
            updatedJsonString = handleCuttingMachine(machineName, machineSetting);
        } else if (machineType.equals(MachineTypeEnum.BANDING.getType())) {
            updatedJsonString = handleBandingMachine(machineName, machineSetting);
        }
        return updatedJsonString;
    }


    private String handleCuttingMachine(String machineName, String machineSetting) {

        String unzipString = unzipString(machineSetting);

        JsonNode cuttingSetting = JsonUtils.parseTree(unzipString);

        JsonNode advancedConfigsRef = cuttingSetting.get("advancedConfigsRef");


        boolean isAutoLabelEnabled = advancedConfigsRef.get("isAutoLabelEnabled") != null && advancedConfigsRef.get("isAutoLabelEnabled").asBoolean();

        if (isAutoLabelEnabled && advancedConfigsRef.get("autoLabelBrand") != null && advancedConfigsRef.get(FIELD_AUTO_LABEL_MODEL) != null) {

            Integer autoLabelModelId = advancedConfigsRef.get(FIELD_AUTO_LABEL_MODEL).asInt();

            try {

                MachineTemplateDO labelingMachineTemplateDO = machineTemplateMapper.selectById(autoLabelModelId);

                MachineTemplateDO labelingMachineDO = MachineTemplateDO.builder()
                        .machineType(labelingMachineTemplateDO.getMachineType())
                        .brandId(labelingMachineTemplateDO.getBrandId())
                        .setting(labelingMachineTemplateDO.getSetting())
                        .name("开料" + machineName + "-贴标机")
                        .build();

                machineTemplateMapper.insert(labelingMachineDO);

                // 创建 ObjectMapper 对象
                ObjectMapper mapper = new ObjectMapper();

                // 将 JSON 字符串解析为 Map
                Map map = mapper.readValue(unzipString, Map.class);

                // 修改值
                Map<String, Object> advancedConfigs = (Map<String, Object>) map.get("advancedConfigsRef");
                advancedConfigs.put(FIELD_AUTO_LABEL_MODEL, labelingMachineDO.getId());

                // 将 Map 转换为 JSON 字符串
                return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(map);

            } catch (Exception e) {

                throw new ServiceException(LABELINGMACHINE_RELATED_DATA_ERROR);
            }

        }

        return null;
    }

    private String handleBandingMachine(String machineName, String machineSetting) {

        String unzipString = unzipString(machineSetting);

        JsonNode drillSetting = JsonUtils.parseTree(unzipString);

        JsonNode cuttingModuleRef = drillSetting.get("cuttingModuleRef");


        boolean isDrillEnabled = cuttingModuleRef.get("isDrillEnabled") != null && cuttingModuleRef.get("isDrillEnabled").asBoolean();

        if (isDrillEnabled && cuttingModuleRef.get("drillBrand") != null && cuttingModuleRef.get(FIELD_DRILL_MODEL) != null) {

            Integer drillModelId = cuttingModuleRef.get(FIELD_DRILL_MODEL).asInt();

            try {

                MachineTemplateDO drillMachineTemplateDO = machineTemplateMapper.selectById(drillModelId);

                MachineTemplateDO drillMachineDO = MachineTemplateDO.builder()
                        .machineType(drillMachineTemplateDO.getMachineType())
                        .brandId(drillMachineTemplateDO.getBrandId())
                        .setting(drillMachineTemplateDO.getSetting())
                        .name("封边" + machineName + "-钻孔机")
                        .build();

                machineTemplateMapper.insert(drillMachineDO);

                // 创建 ObjectMapper 对象
                ObjectMapper mapper = new ObjectMapper();

                // 将 JSON 字符串解析为 Map
                Map map = mapper.readValue(unzipString, Map.class);

                // 修改值
                Map<String, Object> advancedConfigs = (Map<String, Object>) map.get("cuttingModuleRef");
                advancedConfigs.put(FIELD_DRILL_MODEL, drillMachineDO.getId());

                // 将 Map 转换为 JSON 字符串
                return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(map);

            } catch (Exception e) {

                throw new ServiceException(DRILLMACHINE_RELATED_DATA_ERROR);
            }

        }

        return null;
    }


    private void validateMachineTemplateExists(String name, Integer machineType, Long machineId) {

        MachineTemplateDO machineTemplateDO = machineTemplateMapper.selectById(machineId);

        if (machineTemplateDO == null) {
            throw new ServiceException(MACHINE_TEMPLATE_NOT_EXISTS);
        }

        MachineTemplateDO machineTemplate = machineTemplateMapper.selectMachineTemplate(name, machineType, machineId);

        if (machineTemplate != null) {
            throw new ServiceException(MACHINETEMPLATE_NAME_ERROR);
        }

    }


    private void validateMachineTemplate(String name, Integer machineType) {

        MachineTemplateDO machineTemplateDO = machineTemplateMapper.selectMachineTemplateName(name, machineType);


        if (machineTemplateDO != null) {
            throw new ServiceException(MACHINETEMPLATE_NAME_ERROR);
        }

    }

}
