package pwc.taxtech.atms.service.impl;

import com.alibaba.druid.util.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
import org.nutz.lang.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import pwc.taxtech.atms.common.ApplyScope;
import pwc.taxtech.atms.common.CommonUtils;
import pwc.taxtech.atms.common.OperateLogType;
import pwc.taxtech.atms.common.OperationModule;
import pwc.taxtech.atms.constant.enums.KeyValueConfigType;
import pwc.taxtech.atms.dpo.AnalyticsModelDetail;
import pwc.taxtech.atms.dpo.FinancialStatementDetail;
import pwc.taxtech.atms.dpo.TaxReturnDetail;
import pwc.taxtech.atms.dto.AddKeyValueConfigDto;
import pwc.taxtech.atms.dto.KeyValueConfigDisplayDto;
import pwc.taxtech.atms.dto.OperationResultDto;
import pwc.taxtech.atms.dto.UpdateKeyValueConfigDto;
import pwc.taxtech.atms.dto.formula.FormulaConfigDto;
import pwc.taxtech.atms.entity.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class KeyValueConfigServiceImpl extends AbstractService {

    private static final Logger logger = LoggerFactory.getLogger(KeyValueConfigServiceImpl.class);

    private OperateLogType logType = OperateLogType.OperationLogKeyvalue;

    public List<KeyValueConfigDisplayDto> get() {
        List<KeyValueConfig> list = keyValueConfigMapper.selectKeyValueConfigsByOrderByCreateTime();
        List<KeyValueConfigDisplayDto> result = new ArrayList<>();
        if (list.size() > 0) {
            Map<String, String> industryList = new HashMap<>();
            industryMapper.selectByExample(new IndustryExample()).forEach(item -> industryList.put(item.getId(), item.getName()));
            Map<String, String> serviceType = new HashMap<>();
            serviceTypeMapper.selectByExample(new ServiceTypeExample()).forEach(item -> serviceType.put(item.getId(), item.getName()));
            List<KeyValueReference> scopes = keyValueReferenceMapper.selectByExample(new KeyValueReferenceExample());
            for (KeyValueConfig keyValueConfig : list) {
                KeyValueConfigDisplayDto dtoObj = new KeyValueConfigDisplayDto();
                CommonUtils.copyProperties(keyValueConfig, dtoObj);
                dtoObj.setServiceTypes(getNamesByIds(keyValueConfig.getServiceTypeIds(), serviceType));
                dtoObj.setIndustrys(getNamesByIds(keyValueConfig.getIndustryIds(), industryList));
                dtoObj.setIndustryIDs(Arrays.asList(keyValueConfig.getIndustryIds().split(",")));
                dtoObj.setServiceTypeIDs(Arrays.asList(keyValueConfig.getServiceTypeIds().split(",")));
                List<KeyValueReference> selectScopeList = scopes.stream().filter(item -> item.getKeyValueConfigId().equals(keyValueConfig.getId())).collect(Collectors.toList());
                List<Integer> selectScopes = selectScopeList.stream().map(KeyValueReference::getScope).distinct().collect(Collectors.toList());
                Map<Integer, Integer> scopeCount = new HashMap<>();
                if (selectScopeList.size() > 0) {
                    for (Integer selectScope : selectScopes) {
                        Integer count = (int) (selectScopeList.stream().filter(a -> a.getScope().equals(selectScope)).count());
                        scopeCount.put(selectScope, count);
                    }
                }
                dtoObj.setScopeCount(scopeCount);
                dtoObj.setScopeSummary(jointToString(selectScopes));
                result.add(dtoObj);
            }
        }
        return result;
    }

    public OperationResultDto<List<FormulaConfigDto>> getAllFormulaList() {
        OperationResultDto<List<FormulaConfigDto>> result = new OperationResultDto<>();
        List<FormulaConfig> dbItems = formulaConfigMapper.selectByExample(new FormulaConfigExample());
        List<FormulaConfigDto> items = new ArrayList<>();
        CommonUtils.copyProperties(dbItems, items);
        result.setData(items);
        result.setResult(true);
        return result;
    }

    public List<FinancialStatementDetail> getFinacialStatement(String configurationId) {
        Map<String, String> jointObjectMap = new HashMap<>();
        industryMapper.selectByExample(new IndustryExample()).forEach(a -> jointObjectMap.put(a.getId(), a.getName()));
        List<FinancialStatementDetail> referenceFinance = keyValueReferenceMapper.getFinancialStatementDetails(configurationId);
        for (FinancialStatementDetail item : referenceFinance) {
            item.setIndustry(getNamesByIds(item.getIndustry(), jointObjectMap));
        }
        return referenceFinance;
    }

    public List<TaxReturnDetail> getTaxReturn(String configurationId) {
        Map<String, String> jointObjectMap = new HashMap<>();
        industryMapper.selectByExample(new IndustryExample()).forEach(a -> jointObjectMap.put(a.getId(), a.getName()));
        List<TaxReturnDetail> referenceTax = keyValueReferenceMapper.getTaxReturnDetails(configurationId);
        for (TaxReturnDetail item : referenceTax) {
            item.setIndustry(getNamesByIds(item.getIndustry(), jointObjectMap));
        }
        return referenceTax;
    }

    public List<AnalyticsModelDetail> getAnalyticsModel(String configurationId) {
        Map<String, String> industryList = new HashMap<>();
        industryMapper.selectByExample(new IndustryExample()).forEach(a -> industryList.put(a.getId(), a.getName()));
        Map<String, String> organization = new HashMap<>();
        organizationMapper.selectByExample(new OrganizationExample()).forEach(a -> organization.put(a.getId(), a.getName()));
        List<AnalyticsModelDetail> referenceModel = keyValueReferenceMapper.getAnalyticsModelDetails(configurationId);
        for (AnalyticsModelDetail analyticsModelDetail : referenceModel) {
            analyticsModelDetail.setIndustry(getNamesByIds(analyticsModelDetail.getIndustry(), industryList));
            analyticsModelDetail.setEntityName(getNamesByIds(analyticsModelDetail.getEntityId(), organization));
        }
        return referenceModel;
    }

    public int deleteKeyValueConfiguration(String keyId) {
        KeyValueReferenceExample example = new KeyValueReferenceExample();
        example.createCriteria().andKeyValueConfigIdEqualTo(keyId);
        int referenceCount = (int) keyValueReferenceMapper.countByExample(example);
        if (referenceCount == 0) {
            KeyValueConfigExample kvcExample = new KeyValueConfigExample();
            kvcExample.createCriteria().andIdEqualTo(keyId).andKeyValueTypeEqualTo(KeyValueConfigType.Customize.getCode());
            Optional<KeyValueConfig> deleteKey = keyValueConfigMapper.selectByExample(kvcExample).stream().findFirst();
            if (deleteKey.isPresent()) {
                keyValueConfigMapper.deleteByPrimaryKey(deleteKey.get().getId());
                operationLogService.deleteDataAddLog(deleteKey, OperationModule.KeyValueConfig, ""
                        , "DeleteKeyValueConfiguration", "", deleteKey.get().getName(), logType);
                referenceCount = 1;
            }
        } else {
            referenceCount = -1;
        }
        return referenceCount;
    }

    public void addKeyValueConfiguration(AddKeyValueConfigDto addKeyValueConfigDto) {
        Date now = new Date();
        KeyValueConfig keyValueConfig = new KeyValueConfig();
        CommonUtils.copyProperties(addKeyValueConfigDto, keyValueConfig);
        keyValueConfig.setIndustryIds(Strings.join(",", addKeyValueConfigDto.getIndustryIds()));
        keyValueConfig.setServiceTypeIds(Strings.join(",", addKeyValueConfigDto.getServiceTypeIds()));
        String guid = CommonUtils.getUUID();
        keyValueConfig.setId(guid);
        keyValueConfig.setKeyCode(guid.replaceAll("-", ""));
        keyValueConfig.setIsConstant(0);
        keyValueConfig.setCalculateStatus(99);
        keyValueConfig.setCreateTime(now);
        keyValueConfig.setUpdateTime(now);
        keyValueConfig.setUpdator(addKeyValueConfigDto.getUserName());
        keyValueConfig.setKeyValueType(2);

        keyValueConfigMapper.insertSelective(keyValueConfig);
        operationLogService.addDataAddLog(keyValueConfig, OperationModule.KeyValueConfig, addKeyValueConfigDto.getUserName()
                , Message.Log.AddKeyValueConfiguration, "", keyValueConfig.getName(), logType);
    }

    public void updateKeyValueConfiguration(UpdateKeyValueConfigDto updateKeyValueConfigDto) {
        KeyValueConfig keyValueConfig = keyValueConfigMapper.selectByPrimaryKey(updateKeyValueConfigDto.getId());

        if (keyValueConfig == null) {
            throw new InvalidOperationException("Not found");
        }

        KeyValueConfig original = new KeyValueConfig();
        CommonUtils.copyProperties(keyValueConfig, original);
        keyValueConfig.setFormula(updateKeyValueConfigDto.getFormula());
        keyValueConfig.setDescription(updateKeyValueConfigDto.getDescription());
        keyValueConfig.setName(updateKeyValueConfigDto.getName());
        keyValueConfig.setDataSource(updateKeyValueConfigDto.getDataSource());
        keyValueConfig.setServiceTypeIds(Strings.join(",", updateKeyValueConfigDto.getServiceTypeIds()));
        keyValueConfig.setIndustryIds(Strings.join(",", updateKeyValueConfigDto.getIndustryIds()));

        keyValueConfigMapper.updateByPrimaryKey(keyValueConfig);

        operationLogService.updateDataAddLog(original, keyValueConfig, OperationModule.KeyValueConfig
                , updateKeyValueConfigDto.getUserName(), Message.Log.UpdateKeyValueConfiguration
                , keyValueConfig.getName(), "Operation content", logType);
    }

    public boolean isKeyValueDuplicated(String name) {
        KeyValueConfigExample example = new KeyValueConfigExample();
        example.createCriteria().andNameEqualTo(name);
        Optional<KeyValueConfig> keyValueConfig = keyValueConfigMapper.selectByExample(example).stream().findFirst();
        return keyValueConfig.isPresent();
    }

    public List<KeyValueConfigDisplayDto> getByOrgId(String orgId) {
        Organization organization = organizationMapper.selectByPrimaryKey(orgId);
        if (organization == null) {
            return new ArrayList<>();
        }
        KeyValueConfigExample example = new KeyValueConfigExample();
        example.createCriteria().andIndustryIdsLike(organization.getIndustryId());
        List<KeyValueConfig> list = keyValueConfigMapper.selectByExample(example);
        List<KeyValueConfigDisplayDto> result = new ArrayList<>();
        if (list.size() > 0) {
            Map<String, String> industryList = new HashMap<>();
            industryMapper.selectByExample(new IndustryExample()).forEach(a -> industryList.put(a.getId(), a.getName()));
            Map<String, String> serviceType = new HashMap<>();
            serviceTypeMapper.selectByExample(new ServiceTypeExample()).forEach(a -> serviceType.put(a.getId(), a.getName()));
            List<KeyValueReference> scopes = keyValueReferenceMapper.selectByExample(new KeyValueReferenceExample());
            for (KeyValueConfig item : list) {
                KeyValueConfigDisplayDto dtoObj = new KeyValueConfigDisplayDto();
                CommonUtils.copyProperties(item, dtoObj);
                dtoObj.setServiceTypes(getNamesByIds(item.getServiceTypeIds(), serviceType));
                dtoObj.setIndustrys(getNamesByIds(item.getIndustryIds(), industryList));
                dtoObj.setIndustryIDs(new ArrayList<>(Arrays.asList(item.getIndustryIds().split(","))));
                List<Integer> selectScopes = scopes.stream().filter(a -> a.getKeyValueConfigId().equals(item.getId()))
                        .map(KeyValueReference::getScope).collect(Collectors.toList());
                dtoObj.setScopeSummary(jointToString(selectScopes));
                result.add(dtoObj);
            }
        }
        return result;
    }

    private String jointToString(List<Integer> selectScopes) {
        StringBuilder scopeBuilder = new StringBuilder();
        for (Integer selectScope : selectScopes) {
            scopeBuilder.append(ApplyScope.getName(selectScope)).append(",");
        }
        return scopeBuilder.length() > 0 ? scopeBuilder.toString().substring(0, scopeBuilder.length() - 2) : "";
    }

    private String getNamesByIds(String source, Map<String, String> queryList) {
        if (StringUtils.isEmpty(source)) {
            return source;
        }
        String[] sArray = source.split(",");
        List<String> sName = new ArrayList<>();
        for (String s : sArray) {
            if (queryList.containsKey(s)) {
                sName.add(queryList.get(s));
            }
        }
        StringBuilder retStr = new StringBuilder();
        sName.forEach(s -> retStr.append(s).append(","));
        return retStr.toString().substring(0, retStr.length() - 2);
    }

}