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.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.ey.biz.module.system.api.contract.dto.ContractFieldDTO;
import cn.ey.biz.module.system.controller.admin.contract.v2.constant.FieldType;
import cn.ey.biz.module.system.controller.admin.contract.v2.vo.ContractFieldVO;
import cn.ey.biz.module.system.convert.contract.ContractFieldConvert;
import cn.ey.biz.module.system.dal.dataobject.contract.ContractFieldDO;
import cn.ey.biz.module.system.dal.dataobject.contract.ContractSlFieldDO;
import cn.ey.biz.module.system.dal.mapper.contract.ContractFieldMapper;
import cn.ey.biz.module.system.dal.mapper.contract.ContractSlFieldMapper;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static cn.ey.biz.module.system.enums.ErrorCodeConstants.REDUNDANCY_FIELD;

@Service
@Log4j2
public class ContractFieldServiceImpl implements ContractFieldService {

    @Resource
    private ContractFieldMapper contractFieldMapper;

    @Resource
    private ContractSlFieldMapper contractSlFieldMapper;

    @Override
    @Transactional
    public void saveContractField(ContractFieldVO contract) {

        contract.setType(FieldType.FIELD.getName());

        if (contract.getId() != null) {
            if (contractFieldMapper.exists(new LambdaQueryWrapperX<ContractFieldDO>()
                    .eq(ContractFieldDO::getContractModule, contract.getContractModule())
                    .eq(ContractFieldDO::getFieldCode, contract.getFieldCode())
                    .eq(ContractFieldDO::getType, contract.getType())
                    .ne(ContractFieldDO::getId, contract.getId()))) {
                throw ServiceExceptionUtil.exception(REDUNDANCY_FIELD);
            }
            contractFieldMapper.updateById(ContractFieldConvert.INSTANCE.fieldDo2Vo(contract));
        } else {

            if (contractFieldMapper.exists(new LambdaQueryWrapperX<ContractFieldDO>()
                    .eq(ContractFieldDO::getContractModule, contract.getContractModule())
                    .eq(ContractFieldDO::getFieldCode, contract.getFieldCode())
                    .eq(ContractFieldDO::getType, contract.getType()))) {
                throw ServiceExceptionUtil.exception(REDUNDANCY_FIELD);
            }

            ContractFieldDO fieldDO = ContractFieldConvert.INSTANCE.fieldDo2Vo(contract);
            contractFieldMapper.insert(fieldDO);

            Set<String> keys = contractSlFieldMapper.selectList().stream()
                    .map(item -> item.getSl() + ":" + item.getMr() + ":" + item.getContractType()
                            + ":" + item.getType())
                    .collect(Collectors.toSet());

            List<ContractSlFieldDO> slFieldDOS = keys.stream().map(key -> {
                ContractSlFieldDO doo = new ContractSlFieldDO();
                doo.setMr(key.split(":")[1]);
                doo.setContractType(key.split(":")[2]);
                doo.setSl(key.split(":")[0]);
                doo.setFiledId(fieldDO.getId());
                doo.setType(FieldType.FIELD.getName());
                doo.setNeedInput(false);
                doo.setNeedShow(false);
                return doo;
            }).collect(Collectors.toList());

            contractSlFieldMapper.insertBatch(slFieldDOS);
        }
    }

    @Override
    @Transactional
    public void deleteContractField(ContractFieldVO contract) {
        if (contract.getId() != null) {
            contractFieldMapper.deleteById(contract.getId());
            contractSlFieldMapper.delete(new LambdaQueryWrapperX<ContractSlFieldDO>()
                    .eq(ContractSlFieldDO::getFiledId, contract.getId()));
        }
    }

    @Override
    public PageResult<ContractFieldVO> getContractFieldByPage(PageParam pageParam) {
        PageResult<ContractFieldDO> pageResultDo = contractFieldMapper.selectPage(pageParam, new LambdaQueryWrapperX<ContractFieldDO>()
                .eq(ContractFieldDO::getType, FieldType.FIELD.getName()));
        return ContractFieldConvert.INSTANCE.fieldDo2Vo(pageResultDo);
    }

    @Override
    @Transactional
    public PageResult<ContractFieldVO> getContractFieldPageBySl(ContractFieldVO info) {
        LambdaQueryWrapperX<ContractSlFieldDO> query = new LambdaQueryWrapperX<ContractSlFieldDO>()
                .eq(ContractSlFieldDO::getSl, info.getSl())
                .eq(ContractSlFieldDO::getContractType, info.getContractType())
                .eq(ContractSlFieldDO::getMr, info.getMr())
                .eq(ContractSlFieldDO::getType, FieldType.FIELD.getName());

        if (!contractSlFieldMapper.exists(query)) {
            List<ContractSlFieldDO> dos = contractFieldMapper.selectList().stream().map(field -> {
                ContractSlFieldDO doo = new ContractSlFieldDO();
                doo.setFiledId(field.getId());
                doo.setSl(info.getSl());
                doo.setMr(info.getMr());
                doo.setType(FieldType.FIELD.getName());
                doo.setContractType(info.getContractType());
                doo.setNeedInput(false);
                doo.setNeedShow(false);
                return doo;
            }).collect(Collectors.toList());
            contractSlFieldMapper.insertBatch(dos);
        }

        PageResult<ContractFieldVO> page = getContractFieldByPage(info);
        List<ContractSlFieldDO> slRelates = contractSlFieldMapper.selectList(query);

        page.getList().forEach(item -> slRelates.stream()
                .filter(slRelated -> slRelated.getFiledId().equals(item.getFieldId()))
                .findFirst().ifPresent(slRelated -> {
                    item.setId(slRelated.getId());
                    item.setSl(slRelated.getSl());
                    item.setDataSource(slRelated.getDataSource());
                    item.setDefaultValue(slRelated.getDefaultValue());
                    item.setNeedInput(slRelated.getNeedInput());
                    item.setNeedShow(slRelated.getNeedShow());
                }));
        return page;
    }

    @Override
    @Transactional
    public List<ContractFieldDTO> getContractFieldBySl(ContractFieldDTO info) {
        LambdaQueryWrapperX<ContractSlFieldDO> query = new LambdaQueryWrapperX<ContractSlFieldDO>()
                .eq(ContractSlFieldDO::getSl, info.getSl())
                .eq(ContractSlFieldDO::getContractType, info.getContractType())
                .eq(ContractSlFieldDO::getMr, info.getMr())
                .eq(ContractSlFieldDO::getType, FieldType.FIELD.getName());

        if (!contractSlFieldMapper.exists(query)) {
            List<ContractSlFieldDO> dos = contractFieldMapper.selectList().stream().map(field -> {
                ContractSlFieldDO doo = new ContractSlFieldDO();
                doo.setFiledId(field.getId());
                doo.setSl(info.getSl());
                doo.setMr(info.getMr());
                doo.setType(FieldType.FIELD.getName());
                doo.setContractType(info.getContractType());
                doo.setNeedInput(false);
                doo.setNeedShow(false);
                return doo;
            }).collect(Collectors.toList());
            contractSlFieldMapper.insertBatch(dos);
        }

        List<ContractFieldDTO> fields = ContractFieldConvert.INSTANCE.fieldDo2Vo(contractFieldMapper
                .selectList(new LambdaQueryWrapperX<ContractFieldDO>()
                        .eq(ContractFieldDO::getType, FieldType.FIELD.getName())));

        List<ContractSlFieldDO> slRelates = contractSlFieldMapper.selectList(query);


        fields.forEach(item -> slRelates.stream()
                .filter(slRelated -> slRelated.getFiledId().equals(item.getFieldId()))
                .findFirst().ifPresent(slRelated -> {
                    item.setId(slRelated.getId());
                    item.setSl(slRelated.getSl());
                    item.setDataSource(slRelated.getDataSource());
                    item.setDefaultValue(slRelated.getDefaultValue());
                    item.setNeedInput(slRelated.getNeedInput());
                    item.setNeedShow(slRelated.getNeedShow());
                }));
        return fields;
    }


    @Override
    @Transactional
    public void changeShow(ContractFieldVO info) {
        LambdaQueryWrapperX<ContractSlFieldDO> query = new LambdaQueryWrapperX<ContractSlFieldDO>()
                .eq(ContractSlFieldDO::getSl, info.getSl())
                .eq(ContractSlFieldDO::getContractType, info.getContractType())
                .eq(ContractSlFieldDO::getMr, info.getMr())
                .eq(ContractSlFieldDO::getFiledId, info.getFieldId());

        ContractSlFieldDO slFieldDO = contractSlFieldMapper.selectOne(query);
        if (!ObjectUtils.isEmpty(slFieldDO)) {
            slFieldDO.setNeedShow(!slFieldDO.getNeedShow());
            contractSlFieldMapper.updateById(slFieldDO);
        }
    }

    @Override
    @Transactional
    public void changeInput(ContractFieldVO info) {
        LambdaQueryWrapperX<ContractSlFieldDO> query = new LambdaQueryWrapperX<ContractSlFieldDO>()
                .eq(ContractSlFieldDO::getSl, info.getSl())
                .eq(ContractSlFieldDO::getContractType, info.getContractType())
                .eq(ContractSlFieldDO::getMr, info.getMr())
                .eq(ContractSlFieldDO::getFiledId, info.getFieldId());

        ContractSlFieldDO slFieldDO = contractSlFieldMapper.selectOne(query);
        if (!ObjectUtils.isEmpty(slFieldDO)) {
            slFieldDO.setNeedInput(!slFieldDO.getNeedInput());
            contractSlFieldMapper.updateById(slFieldDO);
        }
    }

    @Override
    @Transactional
    public void changeDefaultValue(ContractFieldVO info) {
        LambdaQueryWrapperX<ContractSlFieldDO> query = new LambdaQueryWrapperX<ContractSlFieldDO>()
                .eq(ContractSlFieldDO::getSl, info.getSl())
                .eq(ContractSlFieldDO::getContractType, info.getContractType())
                .eq(ContractSlFieldDO::getMr, info.getMr())
                .eq(ContractSlFieldDO::getFiledId, info.getFieldId());

        ContractSlFieldDO slFieldDO = contractSlFieldMapper.selectOne(query);
        if (!ObjectUtils.isEmpty(slFieldDO)) {
            slFieldDO.setDefaultValue(info.getDefaultValue());
            slFieldDO.setDataSource(info.getDataSource());
            contractSlFieldMapper.updateById(slFieldDO);
        }
    }
}
