package cn.ey.biz.module.system.service.contract;

import cn.ey.biz.common.exception.util.ServiceExceptionUtil;
import cn.ey.biz.common.pojo.PageParam;
import cn.ey.biz.common.pojo.PageResult;
import cn.ey.biz.common.util.json.JsonUtils;
import cn.ey.biz.module.system.api.contract.dto.ContractArchivedFieldDTO;
import cn.ey.biz.module.system.api.contract.dto.ContractTypeDTO;
import cn.ey.biz.module.system.controller.admin.contract.vo.ContractArchivedEpVO;
import cn.ey.biz.module.system.controller.admin.contract.vo.ContractArchivedFieldVO;
import cn.ey.biz.module.system.controller.admin.contract.vo.ContractSaveVO;
import cn.ey.biz.module.system.controller.admin.contract.vo.ContractTypeVO;
import cn.ey.biz.module.system.convert.contract.ContractConvert;
import cn.ey.biz.module.system.dal.dataobject.codeblock.ServiceLineDO;
import cn.ey.biz.module.system.dal.dataobject.contract.ContractDO;
import cn.ey.biz.module.system.dal.mapper.codeblock.ServiceLineMapper;
import cn.ey.biz.module.system.dal.mapper.contract.ContractMapper;
import cn.ey.biz.module.system.dal.redis.contract.ContractRedisDAO;
import cn.ey.biz.module.system.enums.ErrorCodeConstants;
import cn.ey.biz.module.system.enums.contract.ContractTypeEnum;
import cn.ey.biz.module.system.util.PageUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Log4j2
public class ContractServiceImpl implements ContractService {

    @Resource
    private ContractMapper contractMapper;
    @Resource
    private ContractRedisDAO contractRedisDAO;
    @Resource
    private ServiceLineMapper serviceLineMapper;

    private final Pattern empty_type_pattern = Pattern.compile("([0-9]\\.)+0");

    private final String MAIN_LAND = "Mainland";


    @Override
    public PageResult<ContractTypeVO> getContractTypePage(ContractSaveVO<PageParam> pageParam) {
        LambdaQueryWrapper<ContractDO> query = new LambdaQueryWrapper<>();
        ContractDO target = contractMapper.selectOne(query.eq(ContractDO::getSl, pageParam.getServiceLine())
                .eq(ContractDO::getType, pageParam.getType()));
        if (target == null) {
            return PageUtil.getPageList(new ArrayList<>(), pageParam.getContent().getPageSize(),
                    pageParam.getContent().getPageNo());
        }
        List<ContractTypeVO> typeArray = JsonUtils.parseArray(target.getArray(), ContractTypeVO.class);
        return PageUtil.getPageList(typeArray, pageParam.getContent().getPageSize(),
                pageParam.getContent().getPageNo());
    }

    @Override
    public PageResult<ContractArchivedFieldVO> getContractArchivedFieldPage(ContractSaveVO<PageParam> pageParam) {

        ContractDO mainLandTarget = contractMapper.selectOne(new LambdaQueryWrapper<ContractDO>()
                .eq(ContractDO::getSl, MAIN_LAND)
                .eq(ContractDO::getType, ContractTypeEnum.ARCHIVED_FIELD_MANAGE.getType()));
        List<ContractArchivedFieldVO> mainArray;
        if (mainLandTarget == null) {
            mainArray = new ArrayList<>();
        } else {
            mainArray = JsonUtils.parseArray(mainLandTarget.getArray(),
                            ContractArchivedFieldVO.class).stream()
                    .peek(item -> item.setMain(1)).collect(Collectors.toList());
        }

        if (MAIN_LAND.equals(pageParam.getServiceLine())) {
            return PageUtil.getPageList(mainArray, pageParam.getContent().getPageSize(),
                    pageParam.getContent().getPageNo());
        } else {
            ContractDO target = contractMapper.selectOne(new LambdaQueryWrapper<ContractDO>()
                    .eq(ContractDO::getSl, pageParam.getServiceLine())
                    .eq(ContractDO::getType, ContractTypeEnum.ARCHIVED_FIELD_MANAGE.getType())
                    .eq(ContractDO::getSlType, pageParam.getSlType())
                    .eq(ContractDO::getProjectType, pageParam.getProjectType()));

            List<ContractArchivedFieldVO> slArray;
            if (target == null) {
                slArray = new ArrayList<>();
            } else {
                slArray = JsonUtils.parseArray(target.getArray(),
                                ContractArchivedFieldVO.class).stream()
                        .peek(item -> item.setMain(0)).collect(Collectors.toList());
            }

            mainArray.addAll(slArray);

            return PageUtil.getPageList(mainArray, pageParam.getContent().getPageSize(),
                    pageParam.getContent().getPageNo());
        }
    }

    @Override
    public PageResult<ContractArchivedEpVO> getContractArchivedEpPage(ContractSaveVO<PageParam> pageParam) {
        LambdaQueryWrapper<ContractDO> query = new LambdaQueryWrapper<>();
        ContractDO target = contractMapper.selectOne(query.eq(ContractDO::getSl, pageParam.getServiceLine())
                .eq(ContractDO::getType, ContractTypeEnum.ARCHIVED_EP_MANAGE.getType())
                .eq(ContractDO::getProjectType, pageParam.getProjectType()));
        if (target == null) {
            return PageUtil.getPageList(new ArrayList<>(), pageParam.getContent().getPageSize(),
                    pageParam.getContent().getPageNo());
        }
        List<ContractArchivedEpVO> typeArray = JsonUtils.parseArray(target.getArray(), ContractArchivedEpVO.class);
        return PageUtil.getPageList(typeArray, pageParam.getContent().getPageSize(),
                pageParam.getContent().getPageNo());
    }

    @Override
    @Transactional
    public void addContractInfo(ContractSaveVO<Object> contract) {
        if (ContractTypeEnum.CONTRACT_TYPE.getType().equals(contract.getType())) {
            // 合同类型
            ContractSaveVO<ContractTypeVO> converted = contract.convert(ContractTypeVO.class);
            ContractDO target = getTargetContractDoNoException(converted, new LambdaQueryWrapper<>());

            if (target == null && empty_type_pattern.matcher(converted.getContent().getMicroType()).matches()) {
                // 初次添加小类
                target = new ContractDO();
                target.setType(contract.getType());
                target.setSl(contract.getServiceLine());
                String superMainUuid = IdUtil.fastSimpleUUID();
                converted.getContent().setUuid(superMainUuid);
                converted.getContent().setSuperMainUuid(superMainUuid);
                converted.getContent().setMainUuid(superMainUuid);
                // 初始化可控制生效信息
                converted.getContent().setActiveAble(1);
                target.setArray(JsonUtils.toJsonString(new ArrayList<ContractTypeVO>() {{
                    add(converted.getContent());
                }}));
                contractMapper.insert(target);

                serviceLineMapper.selectList().stream().map(ServiceLineDO::getSlCode).collect(Collectors.toList()).forEach(sl -> {
                    ContractDO slTarget = new ContractDO();
                    slTarget.setType(contract.getType());
                    slTarget.setSl(sl);
                    converted.getContent().setUuid(IdUtil.fastSimpleUUID());
                    converted.getContent().setMainUuid(superMainUuid);
                    converted.getContent().setSuperMainUuid(superMainUuid);
                    // SL中不可改变小类
                    converted.getContent().setActiveAble(0);
                    converted.setServiceLine(sl);
                    slTarget.setArray(JsonUtils.toJsonString(new ArrayList<ContractTypeVO>() {{
                        add(converted.getContent());
                    }}));
                    contractMapper.insert(slTarget);
                });

            } else if (target != null && empty_type_pattern.matcher(converted.getContent().getMicroType()).matches()) {
                // 非首次添加小类
                List<ContractTypeVO> typeArray = JsonUtils.parseArray(target.getArray(), ContractTypeVO.class);
                // 查重
                if (typeArray.stream().anyMatch(type -> type.getBigType().equals(converted.getContent().getBigType())
                        && type.getSmallType().equals(converted.getContent().getSmallType()))) {
                    throw ServiceExceptionUtil.exception(ErrorCodeConstants.DUPLICATE_CONTRACT_TYPES);
                }

                String superMainUuid = IdUtil.fastSimpleUUID();
                converted.getContent().setUuid(superMainUuid);
                converted.getContent().setSuperMainUuid(superMainUuid);
                converted.getContent().setMainUuid(superMainUuid);
                // 初始化可控制生效信息
                converted.getContent().setActiveAble(1);
                typeArray.add(converted.getContent());
                target.setArray(JsonUtils.toJsonString(typeArray));
                contractMapper.updateById(target);

                serviceLineMapper.selectList().stream().map(ServiceLineDO::getSlCode).collect(Collectors.toList()).forEach(sl -> {
                    converted.setServiceLine(sl);
                    ContractDO slTarget = getTargetContractDoNoException(converted, new LambdaQueryWrapper<>());

                    List<ContractTypeVO> slTypeArray = JsonUtils.parseArray(slTarget.getArray(), ContractTypeVO.class);

                    slTarget.setType(contract.getType());
                    slTarget.setSl(sl);
                    converted.getContent().setUuid(IdUtil.fastSimpleUUID());
                    converted.getContent().setMainUuid(superMainUuid);
                    converted.getContent().setSuperMainUuid(superMainUuid);
                    // SL中不可改变小类
                    converted.getContent().setActiveAble(0);
                    slTypeArray.add(converted.getContent());
                    slTarget.setArray(JsonUtils.toJsonString(slTypeArray));
                    contractMapper.updateById(slTarget);
                });

            } else if (target != null && !empty_type_pattern.matcher(converted.getContent().getMicroType()).matches()) {
                // 非首次添加细类
                List<ContractTypeVO> typeArray = JsonUtils.parseArray(target.getArray(), ContractTypeVO.class);
                // 确保小类存在
                Optional<ContractTypeVO> targetSmallType = typeArray.stream().filter(type ->
                        type.getBigType().equals(converted.getContent().getBigType())
                                && type.getSmallType().equals(converted.getContent().getSmallType())
                                && empty_type_pattern.matcher(type.getMicroType()).matches()).findFirst();

                if (targetSmallType.isPresent()) {
                    // 查重
                    if (typeArray.stream().anyMatch(type -> type.getBigType().equals(converted.getContent().getBigType())
                            && type.getSmallType().equals(converted.getContent().getSmallType())
                            && type.getMicroType().equals(converted.getContent().getMicroType()))) {
                        throw ServiceExceptionUtil.exception(ErrorCodeConstants.DUPLICATE_CONTRACT_TYPES);
                    }
                    String mainUuid = IdUtil.fastSimpleUUID();
                    converted.getContent().setUuid(mainUuid);
                    converted.getContent().setMainUuid(mainUuid);
                    converted.getContent().setSuperMainUuid(targetSmallType.get().getUuid());
                    // 初始化可控制生效信息
                    converted.getContent().setActiveAble(1);
                    typeArray.add(converted.getContent());
                    target.setArray(JsonUtils.toJsonString(typeArray));
                    contractMapper.updateById(target);

                    serviceLineMapper.selectList().stream().map(ServiceLineDO::getSlCode).collect(Collectors.toList()).forEach(sl -> {
                        converted.setServiceLine(sl);
                        ContractDO slTarget = getTargetContractDoNoException(converted, new LambdaQueryWrapper<>());
                        List<ContractTypeVO> slTypeArray = JsonUtils.parseArray(slTarget.getArray(), ContractTypeVO.class);
                        converted.getContent().setUuid(IdUtil.fastSimpleUUID());
                        converted.getContent().setMainUuid(mainUuid);
                        converted.getContent().setSuperMainUuid(targetSmallType.get().getUuid());
                        // 初始化可控制生效信息
                        converted.getContent().setActiveAble(1);
                        slTypeArray.add(converted.getContent());
                        slTarget.setArray(JsonUtils.toJsonString(slTypeArray));
                        contractMapper.updateById(slTarget);
                    });

                } else {
                    throw ServiceExceptionUtil.exception(ErrorCodeConstants.NO_SMALL_TYPE);
                }
            } else {
                // 首次添加细类报错，缺少对应的小类
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.NO_SMALL_TYPE);
            }

        } else if (ContractTypeEnum.ARCHIVED_FIELD_MANAGE.getType().equals(contract.getType())) {
            // 归档字段
            if ((contract.getProjectType() == null || contract.getProjectType().isEmpty())
                    && !MAIN_LAND.equals(contract.getServiceLine())) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.INVALID_PROJECT_TYPE);
            }

            ContractSaveVO<ContractArchivedFieldVO> converted = contract.convert(ContractArchivedFieldVO.class);
            converted.getContent().setUuid(IdUtil.fastSimpleUUID());
            LambdaQueryWrapper<ContractDO> query = new LambdaQueryWrapper<>();

            // mainland 字段不需要关联projectType && slType
            if (!MAIN_LAND.equals(contract.getServiceLine())) {
                query.eq(ContractDO::getProjectType, contract.getProjectType());
                query.eq(ContractDO::getSlType, contract.getSlType());
            }

            log.info("[GET-CONTRACT]: type={} sl={} slType={} projectType={}",
                    contract.getType(), contract.getServiceLine(), contract.getSlType(), contract.getProjectType());

            ContractDO target = getTargetContractDoNoException(converted, query);

            log.info("[GET-CONTRACT]: {}", target);

            addContractArchivedField(converted, target);

        } else if (ContractTypeEnum.ARCHIVED_EP_MANAGE.getType().equals(contract.getType())) {

            if (contract.getProjectType() == null || contract.getProjectType().isEmpty()) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.INVALID_PROJECT_TYPE);
            }

            ContractSaveVO<ContractArchivedEpVO> converted = contract.convert(ContractArchivedEpVO.class);
            converted.getContent().setUuid(IdUtil.fastSimpleUUID());
            LambdaQueryWrapper<ContractDO> query = new LambdaQueryWrapper<>();
            query.eq(ContractDO::getProjectType, contract.getProjectType());
            ContractDO target = getTargetContractDoNoException(converted, query);
            addContractArchivedEp(converted, target);
        }
    }

    @Override
    @Transactional
    public void updateContractType(ContractSaveVO<Object> contract) {
        if (ContractTypeEnum.CONTRACT_TYPE.getType().equals(contract.getType())) {
            ContractSaveVO<ContractTypeVO> converted = contract.convert(ContractTypeVO.class);
            ContractDO target = getTargetContractDo(contract, new LambdaQueryWrapper<>());
            List<ContractTypeVO> typeArray = JsonUtils.parseArray(target.getArray(), ContractTypeVO.class);

            // 检查uuid
            if (typeArray.stream().noneMatch(type -> type.getUuid().equals(converted.getContent().getUuid())
                    || type.getMainUuid().equals(converted.getContent().getMainUuid())
                    || type.getSuperMainUuid().equals(converted.getContent().getSuperMainUuid()))) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.UUID_NOT_EXISTS,
                        converted.getContent().getUuid());
            }

            // 查重
            if (typeArray.stream().anyMatch(type -> type.getBigType().equals(converted.getContent().getBigType())
                    && type.getSmallType().equals(converted.getContent().getSmallType())
                    && type.getMicroType().equals(converted.getContent().getMicroType())
                    && !type.getUuid().equals(converted.getContent().getUuid()))) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.DUPLICATE_CONTRACT_TYPES);
            }

            // 确保小类存在
            Optional<ContractTypeVO> targetSmallType = typeArray.stream().filter(type ->
                    type.getBigType().equals(converted.getContent().getBigType())
                            && type.getSmallType().equals(converted.getContent().getSmallType())
                            && empty_type_pattern.matcher(type.getMicroType()).matches()).findFirst();

            if (targetSmallType.isPresent()) {
                // 更新数组结构
                typeArray.forEach(type -> {
                    if (empty_type_pattern.matcher(converted.getContent().getMicroType()).matches() ?
                            type.getSuperMainUuid().equals(converted.getContent().getSuperMainUuid())
                            : type.getMainUuid().equals(converted.getContent().getMainUuid())) {
                        type.setBigType(converted.getContent().getBigType());
                        type.setSmallType(converted.getContent().getSmallType());
                        if (!empty_type_pattern.matcher(converted.getContent().getMicroType()).matches()) {
                            type.setMicroType(converted.getContent().getMicroType());
                        }
                        type.setForbidden(converted.getContent().getForbidden());
                        type.setPerson(converted.getContent().getPerson());
                    }
                });

                target.setArray(JsonUtils.toJsonString(typeArray));
                contractMapper.updateById(target);

                serviceLineMapper.selectList().stream().map(ServiceLineDO::getSlCode).collect(Collectors.toList()).forEach(sl -> {
                    contract.setServiceLine(sl);
                    ContractDO slTarget = getTargetContractDo(contract, new LambdaQueryWrapper<>());
                    List<ContractTypeVO> slTypeArray = JsonUtils.parseArray(slTarget.getArray(), ContractTypeVO.class);
                    slTypeArray.forEach(type -> {
                        if (empty_type_pattern.matcher(converted.getContent().getMicroType()).matches() ?
                                type.getSuperMainUuid().equals(converted.getContent().getSuperMainUuid())
                                : type.getMainUuid().equals(converted.getContent().getMainUuid())) {
                            type.setBigType(converted.getContent().getBigType());
                            type.setSmallType(converted.getContent().getSmallType());
                            if (!empty_type_pattern.matcher(converted.getContent().getMicroType()).matches()) {
                                type.setMicroType(converted.getContent().getMicroType());
                            }
                            type.setForbidden(converted.getContent().getForbidden());
                            type.setPerson(converted.getContent().getPerson());
                        }
                    });
                    slTarget.setArray(JsonUtils.toJsonString(slTypeArray));
                    contractMapper.updateById(slTarget);
                });
            } else {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.NO_SMALL_TYPE);
            }


        } else if (ContractTypeEnum.ARCHIVED_FIELD_MANAGE.getType().equals(contract.getType())) {
            LambdaQueryWrapper<ContractDO> query = new LambdaQueryWrapper<>();


            // mainland 字段不需要关联projectType && slType
            if (!MAIN_LAND.equals(contract.getServiceLine())) {
                query.eq(ContractDO::getProjectType, contract.getProjectType());
                query.eq(ContractDO::getSlType, contract.getSlType());
            }

            ContractDO target = getTargetContractDo(contract, query);

            ContractSaveVO<ContractArchivedFieldVO> converted = contract.convert(ContractArchivedFieldVO.class);
            // 检查UUID是否正确传递
            if (converted.getContent().getUuid() == null || converted.getContent().getUuid().isEmpty()) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.INVALID_UUID);
            }

            updateContractArchivedFields(converted, target);
        } else if (ContractTypeEnum.ARCHIVED_EP_MANAGE.getType().equals(contract.getType())) {
            LambdaQueryWrapper<ContractDO> query = new LambdaQueryWrapper<>();

            // mainland 字段不需要关联projectType
            if (!MAIN_LAND.equals(contract.getServiceLine())) {
                query.eq(ContractDO::getProjectType, contract.getProjectType());
            }

            ContractDO target = getTargetContractDo(contract, query);
            ContractSaveVO<ContractArchivedEpVO> converted = contract.convert(ContractArchivedEpVO.class);

            // 检查UUID是否正确传递
            if (converted.getContent().getUuid() == null || converted.getContent().getUuid().isEmpty()) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.INVALID_UUID);
            }

            updateContractArchivedEp(converted, target);
        }
    }

    @Override
    @Transactional
    public void deleteContractType(ContractSaveVO<Object> contract) {

        if (ContractTypeEnum.CONTRACT_TYPE.getType().equals(contract.getType())) {
            ContractSaveVO<ContractTypeVO> converted = contract.convert(ContractTypeVO.class);
            // 检查UUID是否正确传递
            if (converted.getContent().getUuid() == null || converted.getContent().getUuid().isEmpty()) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.INVALID_UUID);
            }

            ContractDO target = getTargetContractDo(contract, new LambdaQueryWrapper<>());
            deleteContractType(converted, target);

            serviceLineMapper.selectList().stream().map(ServiceLineDO::getSlCode).collect(Collectors.toList()).forEach(sl -> {
                converted.getContent().setMainUuid(converted.getContent().getMainUuid());
                converted.setServiceLine(sl);
                ContractDO slTarget = getTargetContractDoNoException(converted, new LambdaQueryWrapper<>());
                deleteContractType(converted, slTarget);
            });

        } else if (ContractTypeEnum.ARCHIVED_FIELD_MANAGE.getType().equals(contract.getType())) {
            LambdaQueryWrapper<ContractDO> query = new LambdaQueryWrapper<>();

            // mainland 字段不需要关联projectType && slType
            if (!MAIN_LAND.equals(contract.getServiceLine())) {
                query.eq(ContractDO::getProjectType, contract.getProjectType());
                query.eq(ContractDO::getSlType, contract.getSlType());
            }

            ContractDO target = getTargetContractDo(contract, query);
            ContractSaveVO<ContractArchivedFieldVO> converted = contract.convert(ContractArchivedFieldVO.class);
            // 检查UUID是否正确传递
            if (converted.getContent().getUuid() == null || converted.getContent().getUuid().isEmpty()) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.INVALID_UUID);
            }
            deleteContractArchivedField(converted, target);

        } else if (ContractTypeEnum.ARCHIVED_EP_MANAGE.getType().equals(contract.getType())) {
            LambdaQueryWrapper<ContractDO> query = new LambdaQueryWrapper<>();

            // mainland 字段不需要关联projectType
            if (!MAIN_LAND.equals(contract.getServiceLine())) {
                query.eq(ContractDO::getProjectType, contract.getProjectType());
            }

            ContractDO target = getTargetContractDo(contract, query);
            ContractSaveVO<ContractArchivedEpVO> converted = contract.convert(ContractArchivedEpVO.class);

            // 检查UUID是否正确传递
            if (converted.getContent().getUuid() == null || converted.getContent().getUuid().isEmpty()) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.INVALID_UUID);
            }

            deleteContractArchivedEp(converted, target);
        }
    }

    @Override
    public List<ContractTypeDTO> getTypes(String sl) {
        LambdaQueryWrapper<ContractDO> query = new LambdaQueryWrapper<>();
        ContractDO target = contractMapper.selectOne(query.eq(ContractDO::getSl, sl)
                .eq(ContractDO::getType, ContractTypeEnum.CONTRACT_TYPE.getType()));
        if (target == null) {
            return new ArrayList<>();
        }

        // 获取生效的类型
        final List<ContractTypeVO> typeArray = JsonUtils.parseArray(target.getArray(), ContractTypeVO.class)
                .stream().filter(type -> type.getActive().equals(1)).collect(Collectors.toList());

        return typeArray.stream().map(ContractTypeVO::getBigType).distinct().map(bigTypeName -> {
            ContractTypeDTO bigDto = new ContractTypeDTO();
            bigDto.setName(bigTypeName);
            bigDto.setChildren(typeArray.stream().filter(type -> type.getBigType().equals(bigTypeName))
                    .map(ContractTypeVO::getSmallType).distinct().map(smallTypeName -> {
                        ContractTypeDTO smallDto = new ContractTypeDTO();
                        smallDto.setName(smallTypeName);
                        smallDto.setChildren(typeArray.stream().filter(type -> type.getBigType().equals(bigTypeName)
                                && type.getSmallType().equals(smallTypeName)).map(microType -> {
                            ContractTypeDTO microDto = new ContractTypeDTO();
                            microDto.setUuid(microType.getUuid());
                            microDto.setName(microType.getMicroType());
                            return microDto;
                        }).collect(Collectors.toList()));
                        return smallDto;
                    }).collect(Collectors.toList()));
            return bigDto;
        }).collect(Collectors.toList());
    }


    @Override
    public void putTypeActive(ContractSaveVO<ContractTypeVO> content) {
        // 检查UUID是否正确传递
        if (content.getContent().getUuid() == null || content.getContent().getUuid().isEmpty()) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.INVALID_UUID);
        }
        ContractDO target = getTargetContractDo(content, new LambdaQueryWrapper<>());
        List<ContractTypeVO> typeArray = JsonUtils.parseArray(target.getArray(), ContractTypeVO.class);

        if (typeArray.stream().noneMatch(type -> type.getUuid().equals(content.getContent().getUuid())
                || type.getMainUuid().equals(content.getContent().getMainUuid())
                || type.getSuperMainUuid().equals(content.getContent().getSuperMainUuid()))) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.UUID_NOT_EXISTS,
                    content.getContent().getUuid());
        }

        if (MAIN_LAND.equals(content.getServiceLine())) {
            // MainLand 中修改
            if (empty_type_pattern.matcher(content.getContent().getMicroType()).matches()) {
                // 修改小类
                typeArray.forEach(type -> {
                    if (type.getSuperMainUuid().equals(content.getContent().getSuperMainUuid())) {
                        type.setActive(content.getContent().getActive());
                        if (!type.getUuid().equals(type.getSuperMainUuid())) {
                            // MainLand下小类无效时，细类不可以起效
                            type.setActiveAble(content.getContent().getActive());
                        }
                    }
                });
                target.setArray(JsonUtils.toJsonString(typeArray));
                contractMapper.updateById(target);

                serviceLineMapper.selectList().stream().map(ServiceLineDO::getSlCode).collect(Collectors.toList()).forEach(sl -> {
                    content.setServiceLine(sl);
                    ContractDO slTarget = getTargetContractDoNoException(content, new LambdaQueryWrapper<>());
                    List<ContractTypeVO> slTypeArray = JsonUtils.parseArray(slTarget.getArray(), ContractTypeVO.class);
                    slTypeArray.forEach(type -> {
                        if (type.getSuperMainUuid().equals(content.getContent().getSuperMainUuid())) {
                            type.setActive(content.getContent().getActive());
                            type.setActiveAble(content.getContent().getActive());
                        }
                    });
                    slTarget.setArray(JsonUtils.toJsonString(slTypeArray));
                    contractMapper.updateById(slTarget);
                });

            } else {
                // 修改细类
                typeArray.forEach(type -> {
                    if (type.getUuid().equals(content.getContent().getUuid())) {
                        type.setActive(content.getContent().getActive());
                    }
                });
                target.setArray(JsonUtils.toJsonString(typeArray));
                contractMapper.updateById(target);

                serviceLineMapper.selectList().stream().map(ServiceLineDO::getSlCode).collect(Collectors.toList()).forEach(sl -> {
                    content.setServiceLine(sl);
                    ContractDO slTarget = getTargetContractDoNoException(content, new LambdaQueryWrapper<>());
                    List<ContractTypeVO> slTypeArray = JsonUtils.parseArray(slTarget.getArray(), ContractTypeVO.class);
                    slTypeArray.forEach(type -> {
                        if (type.getMainUuid().equals(content.getContent().getMainUuid())) {
                            type.setActive(content.getContent().getActive());
                            type.setActiveAble(content.getContent().getActive());
                        }
                    });
                    slTarget.setArray(JsonUtils.toJsonString(slTypeArray));
                    contractMapper.updateById(slTarget);
                });
            }
        } else {
            // SL 中修改
            typeArray.forEach(type -> {
                if (type.getUuid().equals(content.getContent().getUuid())) {
                    type.setActive(content.getContent().getActive());
                }
            });
            target.setArray(JsonUtils.toJsonString(typeArray));
            contractMapper.updateById(target);
        }
    }

    @Override
    public List<ContractArchivedFieldDTO> getContractArchivedFields(String sl, String projectType, String slType) {

        ContractDO mainLandTarget = contractMapper.selectOne(new LambdaQueryWrapper<ContractDO>()
                .eq(ContractDO::getSl, MAIN_LAND)
                .eq(ContractDO::getType, ContractTypeEnum.ARCHIVED_FIELD_MANAGE.getType()));
        List<ContractArchivedFieldVO> mainArray;
        if (mainLandTarget == null) {
            mainArray = new ArrayList<>();
        } else {
            mainArray = JsonUtils.parseArray(mainLandTarget.getArray(),
                            ContractArchivedFieldVO.class).stream()
                    .peek(item -> item.setMain(1)).collect(Collectors.toList());
        }

        if (MAIN_LAND.equals(sl)) {
            return ContractConvert.INSTANCE.convertFields(mainArray);
        } else {
            ContractDO target = contractMapper.selectOne(new LambdaQueryWrapper<ContractDO>()
                    .eq(ContractDO::getSl, sl)
                    .eq(ContractDO::getType, ContractTypeEnum.ARCHIVED_FIELD_MANAGE.getType())
                    .eq(ContractDO::getSlType, slType)
                    .eq(ContractDO::getProjectType, projectType));


            if (target == null) {
                target = new ContractDO();
            }

            List<ContractArchivedFieldVO> slArray = JsonUtils.parseArray(target.getArray(),
                            ContractArchivedFieldVO.class).stream()
                    .peek(item -> item.setMain(0)).collect(Collectors.toList());
            mainArray.addAll(slArray);

            return ContractConvert.INSTANCE.convertFields(mainArray);
        }
    }

    private Boolean checkRedundant(ContractArchivedFieldVO archivedVO, List<ContractArchivedFieldVO> typeArray) {
        return typeArray.stream().anyMatch(type -> type.getModel().equals(archivedVO.getModel())
                && type.getCode().equals(archivedVO.getCode()));
    }

    private Boolean checkRedundant(ContractArchivedEpVO archivedVO, List<ContractArchivedEpVO> typeArray) {
        return typeArray.stream().anyMatch(type -> type.getName().equals(archivedVO.getName())
                && type.getMail().equals(archivedVO.getMail()) && type.getSl().equals(archivedVO.getSl()));
    }

    /**
     * 添加 归档字段
     *
     * @param contract 新加内容
     * @param target   数据库中的存储内容
     */
    private void addContractArchivedField(ContractSaveVO<ContractArchivedFieldVO> contract, ContractDO target) {
        if (target == null) {
            target = new ContractDO();
            target.setType(contract.getType());
            target.setSl(contract.getServiceLine());
            target.setSlType(contract.getSlType());

            // mainland 字段不需要关联projectType
            if (!MAIN_LAND.equals(contract.getServiceLine())) {
                target.setProjectType(contract.getProjectType());
            }
            target.setArray(JsonUtils.toJsonString(new ArrayList<ContractArchivedFieldVO>() {{
                add(contract.getContent());
            }}));

            int result = contractMapper.insert(target);

            log.info("[ADD CONTRACT FIELD]: type={} sl={} slType={} projectType={} result={}.",
                    contract.getType(), contract.getServiceLine(), contract.getSlType(), contract.getProjectType(), result);
        } else {
            List<ContractArchivedFieldVO> typeArray = JsonUtils.parseArray(target.getArray(), ContractArchivedFieldVO.class);
            if (checkRedundant(contract.getContent(), typeArray)) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.DUPLICATE_CONTRACT_ARCHIVES);
            }
            typeArray.add(contract.getContent());
            target.setArray(JsonUtils.toJsonString(typeArray));
            contractMapper.updateById(target);

            log.info("[UPDATE CONTRACT FIELD]: type={} sl={} slType={} projectType={} result_id={}.",
                    contract.getType(), contract.getServiceLine(), contract.getSlType(), contract.getProjectType(), target.getId());
        }
    }

    /**
     * 删除 归档字段
     *
     * @param contract 删除内容
     * @param target   数据库中的存储内容
     */
    private void deleteContractArchivedField(ContractSaveVO<ContractArchivedFieldVO> contract, ContractDO target) {
        List<ContractArchivedFieldVO> typeArray = JsonUtils.parseArray(target.getArray(), ContractArchivedFieldVO.class);
        if (typeArray.stream().noneMatch(type -> type.getUuid().equals(contract.getContent().getUuid()))) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.UUID_NOT_EXISTS,
                    contract.getContent().getUuid());
        }
        typeArray = typeArray.stream().filter(type -> !type.getUuid().equals(contract.getContent().getUuid()))
                .collect(Collectors.toList());
        target.setArray(JsonUtils.toJsonString(typeArray));
        contractMapper.updateById(target);
    }

    /**
     * 更新 归档字段
     *
     * @param contract 更新内容
     * @param target   数据库中的存储内容
     */
    private void updateContractArchivedFields(ContractSaveVO<ContractArchivedFieldVO> contract, ContractDO target) {
        List<ContractArchivedFieldVO> typeArray = JsonUtils.parseArray(target.getArray(), ContractArchivedFieldVO.class);
        if (typeArray.stream().noneMatch(type -> type.getUuid().equals(contract.getContent().getUuid()))) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.UUID_NOT_EXISTS,
                    contract.getContent().getUuid());
        }

        if (typeArray.stream().anyMatch(type -> type.getCode().equals(contract.getContent().getCode())
                && !type.getUuid().equals(contract.getContent().getUuid()))) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.DUPLICATE_CONTRACT_TYPES);
        }

        // 更新数组结构
        typeArray.forEach(type -> {
            if (type.getUuid().equals(contract.getContent().getUuid())) {
                type.setCategory(contract.getContent().getCategory());
                type.setCode(contract.getContent().getCode());
                type.setModel(contract.getContent().getModel());
                type.setName(contract.getContent().getName());
                type.setNeed(contract.getContent().getNeed());
                type.setShow(contract.getContent().getShow());
                type.setRemark(contract.getContent().getRemark());
            }
        });

        target.setArray(JsonUtils.toJsonString(typeArray));
        contractMapper.updateById(target);
    }

    private void addContractArchivedEp(ContractSaveVO<ContractArchivedEpVO> contract, ContractDO target) {
        if (target == null) {
            target = new ContractDO();
            target.setType(contract.getType());
            target.setSl(contract.getServiceLine());
            target.setProjectType(contract.getProjectType());
            target.setArray(JsonUtils.toJsonString(new ArrayList<ContractArchivedEpVO>() {{
                add(contract.getContent());
            }}));
            contractMapper.insert(target);
        } else {
            List<ContractArchivedEpVO> typeArray = JsonUtils.parseArray(target.getArray(),
                    ContractArchivedEpVO.class);
            if (checkRedundant(contract.getContent(), typeArray)) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.DUPLICATE_CONTRACT_ARCHIVES);
            }
            typeArray.add(contract.getContent());
            target.setArray(JsonUtils.toJsonString(typeArray));
            contractMapper.updateById(target);
        }

        // 更新缓存
        List<ContractDO> contractDOS = contractMapper.selectList(new LambdaUpdateWrapper<ContractDO>()
                .eq(ContractDO::getType, contract.getType()));
        setRidesSl(contractDOS);
    }

    private ContractDO getTargetContractDo(ContractSaveVO<?> contract, LambdaQueryWrapper<ContractDO> query) {
        query = query.eq(ContractDO::getSl, contract.getServiceLine());
        query = query.eq(ContractDO::getType, contract.getType());
        ContractDO target = contractMapper.selectOne(query);
        if (target == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.INVALID_UPDATE_TYPE,
                    contract.getServiceLine(), contract.getType());
        }
        return target;
    }

    private ContractDO getTargetContractDoNoException(ContractSaveVO<?> contract, LambdaQueryWrapper<ContractDO> query) {
        query = query.eq(ContractDO::getSl, contract.getServiceLine());
        query = query.eq(ContractDO::getType, contract.getType());
        return contractMapper.selectOne(query);
    }

    private void deleteContractType(ContractSaveVO<ContractTypeVO> contract, ContractDO target) {
        List<ContractTypeVO> typeArray = JsonUtils.parseArray(target.getArray(), ContractTypeVO.class);
        if (typeArray.stream().noneMatch(type -> type.getMainUuid().equals(contract.getContent().getMainUuid()))) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.UUID_NOT_EXISTS,
                    contract.getContent().getUuid());
        }

        // 删除数组结构
        typeArray = typeArray.stream().filter(type -> !type.getMainUuid().equals(contract.getContent().getMainUuid()))
                .collect(Collectors.toList());

        target.setArray(JsonUtils.toJsonString(typeArray));
        contractMapper.updateById(target);
    }


    private void deleteContractArchivedEp(ContractSaveVO<ContractArchivedEpVO> contract, ContractDO target) {
        List<ContractArchivedEpVO> typeArray = JsonUtils.parseArray(target.getArray(), ContractArchivedEpVO.class);
        if (typeArray.stream().noneMatch(type -> type.getUuid().equals(contract.getContent().getUuid()))) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.UUID_NOT_EXISTS,
                    contract.getContent().getUuid());
        }
        typeArray = typeArray.stream().filter(type -> !type.getUuid().equals(contract.getContent().getUuid()))
                .collect(Collectors.toList());
        target.setArray(JsonUtils.toJsonString(typeArray));
        contractMapper.updateById(target);

        // 更新缓存
        List<ContractDO> contractDOS = contractMapper.selectList(new LambdaUpdateWrapper<ContractDO>()
                .eq(ContractDO::getType, contract.getType()));
        setRidesSl(contractDOS);
    }

    private void updateContractArchivedEp(ContractSaveVO<ContractArchivedEpVO> contract, ContractDO target) {
        List<ContractArchivedEpVO> typeArray = JsonUtils.parseArray(target.getArray(), ContractArchivedEpVO.class);
        if (typeArray.stream().noneMatch(type -> type.getUuid().equals(contract.getContent().getUuid()))) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.UUID_NOT_EXISTS,
                    contract.getContent().getUuid());
        }

        if (typeArray.stream().anyMatch(type -> type.getName().equals(contract.getContent().getName())
                && !type.getUuid().equals(contract.getContent().getUuid()))) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.DUPLICATE_CONTRACT_TYPES);
        }

        // 更新数组结构
        typeArray.forEach(type -> {
            if (type.getUuid().equals(contract.getContent().getUuid())) {
                type.setActive(contract.getContent().getActive());
                type.setMail(contract.getContent().getMail());
                type.setSl(contract.getContent().getSl());
                type.setName(contract.getContent().getName());
            }
        });

        target.setArray(JsonUtils.toJsonString(typeArray));
        contractMapper.updateById(target);

        // 更新缓存
        List<ContractDO> contractDOS = contractMapper.selectList(new LambdaUpdateWrapper<ContractDO>()
                .eq(ContractDO::getType, contract.getType()));
        setRidesSl(contractDOS);
    }

    @Override
    public List<String> getSl(String name) {
        String slList = contractRedisDAO.getRedisSl(name);
        List<String> listdd = JSONArray.parseArray(slList, String.class);
        return listdd;
    }

    public void setRidesSl(List<ContractDO> contractDOS) {
        if (CollectionUtil.isNotEmpty(contractDOS)) {
            Map<String, Object> mapRedis = new HashMap<>();
            for (ContractDO ccont : contractDOS) {
                List<ContractArchivedEpVO> list = JSONArray.parseArray(ccont.getArray(), ContractArchivedEpVO.class);
                if (CollectionUtil.isNotEmpty(list)) {
                    for (ContractArchivedEpVO li : list) {
                        if (mapRedis.containsKey(li.getName())) {
                            Object value = mapRedis.get(li.getName());
                            List<String> listdd = JSONArray.parseArray(JSON.toJSONString(value), String.class);
                            listdd.add((ccont.getSl()));
                            listdd = listdd.stream().distinct().collect(Collectors.toList());   //去重
                            mapRedis.put(li.getName(), (listdd));
                        } else {
                            Set<String> listre = new TreeSet<>();
                            listre.add(ccont.getSl());
                            mapRedis.put(li.getName(), listre);
                        }
                    }
                }
            }
            contractRedisDAO.updateArchivedEP(mapRedis);
        }
    }

}
