package pwc.taxtech.atms.service.impl;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import pwc.taxtech.atms.common.ApplyScope;
import pwc.taxtech.atms.common.CommonUtils;
import pwc.taxtech.atms.constant.enums.CellDataSourceType;
import pwc.taxtech.atms.dto.CellTemplateConfigDto;
import pwc.taxtech.atms.dto.OperationResultDto;
import pwc.taxtech.atms.entity.CellTemplate;
import pwc.taxtech.atms.entity.CellTemplateConfig;
import pwc.taxtech.atms.entity.CellTemplateConfigExample;
import pwc.taxtech.atms.entity.CellTemplateExample;
import pwc.taxtech.atms.entity.FormulaConfig;
import pwc.taxtech.atms.entity.FormulaConfigExample;
import pwc.taxtech.atms.entity.KeyValueConfig;
import pwc.taxtech.atms.entity.KeyValueConfigExample;
import pwc.taxtech.atms.entity.KeyValueReference;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CellTemplateServiceImpl extends AbstractService {

    public OperationResultDto<List<CellTemplateConfigDto>> getCellConfigList(Long templateId) {
        OperationResultDto<List<CellTemplateConfigDto>> result = new OperationResultDto<>();
        CellTemplateExample example = new CellTemplateExample();
        example.createCriteria().andReportTemplateIdEqualTo(templateId);
        List<CellTemplate> cellTemplateList = cellTemplateMapper.selectByExample(example);
        List<CellTemplateConfig> configList = cellTemplateConfigMapper.getCellTemplateConfigByTemplateId(templateId);
        if (cellTemplateList.isEmpty()) {
            result.setData(Collections.emptyList());
            return result;
        }

        List<CellTemplateConfigDto> rData = new ArrayList<>();
        for (CellTemplate x : cellTemplateList) {
            CellTemplateConfigDto cellTemplateConfigDto = getConfigDto(x, configList.stream()
                    .filter(a -> a.getCellTemplateId().equals(x.getId()))
                    .collect(Collectors.toList()));
            if (cellTemplateConfigDto != null) {
                rData.add(cellTemplateConfigDto);
            }
        }

        if (rData.size() > 0) {
            result.setResult(true);
            result.setData(rData);
        } else {
            result.setData(Collections.emptyList());
        }
        return result;
    }

    public OperationResultDto<CellTemplateConfigDto> getCellConfig(Long cellTemplateId) {
        OperationResultDto<CellTemplateConfigDto> result = new OperationResultDto<>();
        CellTemplate config = cellTemplateMapper.selectByPrimaryKey(cellTemplateId);

        if (config == null) {
            result.setResultMsg("NoData");
            return result;
        }

        CellTemplateConfigExample example = new CellTemplateConfigExample();
        example.createCriteria().andCellTemplateIdEqualTo(cellTemplateId);
        List<CellTemplateConfig> configList = cellTemplateConfigMapper.selectByExample(example);
        result.setData(getConfigDto(config, configList));

        if (result.getData() == null) {
            result.setResultMsg("NoData");
            return result;
        }

        result.setResult(true);
        return result;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public OperationResultDto saveOrEdit(CellTemplateConfigDto cellTemplateConfig) {
        OperationResultDto result = new OperationResultDto();
        CellTemplate cellTemplate = cellTemplateMapper.selectByPrimaryKey(Long.parseLong(cellTemplateConfig.getCellTemplateId()));
        if (cellTemplate == null) {
            result.setResultMsg("Nodata");
            return result;
        }
        cellTemplate.setComment(cellTemplateConfig.getFormulaDescription());
        cellTemplate.setRowName(cellTemplateConfig.getRowName());
        cellTemplate.setColumnName(cellTemplateConfig.getColumnName());
        cellTemplateMapper.updateByPrimaryKey(cellTemplate);
        CellTemplateConfigExample example = new CellTemplateConfigExample();
        example.createCriteria().andCellTemplateIdEqualTo(Long.parseLong(cellTemplateConfig.getCellTemplateId()));
        List<CellTemplateConfig> cellTemplateConfigs = cellTemplateConfigMapper.selectByExample(example);

        if (!cellTemplateConfigs.isEmpty()) {
            for (CellTemplateConfig templateConfig : cellTemplateConfigs) {
                cellTemplateConfigMapper.deleteByPrimaryKey(templateConfig.getId());
            }
        }

        List<String> keyValues = new ArrayList<>();
        OperationResultDto<List<CellTemplateConfig>> configResult = getConfigList(cellTemplateConfig, keyValues);
        if (configResult.getResult()) {
            configResult.getData().forEach(a -> cellTemplateConfigMapper.insertSelective(a));
        }

        if (keyValues.size() > 0) {
            keyValues.forEach(a -> {
                KeyValueReference keyValueReferenceData = new KeyValueReference();
                keyValueReferenceData.setId(CommonUtils.getUUID());
                keyValueReferenceData.setKeyValueConfigId(a);
                keyValueReferenceData.setScope(ApplyScope.TaxReturn.value());
                keyValueReferenceData.setCellTemplateId(cellTemplate.getId());
                keyValueReferenceMapper.insertSelective(keyValueReferenceData);
            });
        }
        result.setResult(true);
        result.setResultMsg(configResult.getResultMsg());
        return result;
    }

    private OperationResultDto<List<CellTemplateConfig>> getConfigList(CellTemplateConfigDto cellTemplateConfigDto, List<String> keyValueIds) {
        OperationResultDto<List<CellTemplateConfig>> operationResultDto = new OperationResultDto<>();
        List<CellTemplateConfig> cellTemplateConfigList = new ArrayList<>();

        if (cellTemplateConfigDto.getHasFormula() != null && cellTemplateConfigDto.getHasFormula()) {
            operationResultDto.setResultMsg(getFormulaDataSource(cellTemplateConfigDto.getFormula(), keyValueIds));
            CellTemplateConfig cellTemplateConfig = new CellTemplateConfig();
            cellTemplateConfig.setId(distributedIdService.nextId());
            cellTemplateConfig.setCellTemplateId(Long.parseLong(cellTemplateConfigDto.getCellTemplateId()));
            cellTemplateConfig.setReportTemplateId(Long.parseLong(cellTemplateConfigDto.getTemplateId()));
            cellTemplateConfig.setCreateBy(cellTemplateConfigDto.getCreator());
            cellTemplateConfig.setUpdateBy(cellTemplateConfigDto.getUpdater());
            cellTemplateConfig.setUpdateTime(new Date());
            cellTemplateConfig.setCreateTime(new Date());
            cellTemplateConfig.setDataSourceType(CellDataSourceType.Formula.getCode());
            cellTemplateConfig.setFormulaDataSource(operationResultDto.getResultMsg());
            cellTemplateConfig.setFormula(cellTemplateConfigDto.getFormula());
            cellTemplateConfig.setFormulaDescription(cellTemplateConfigDto.getFormulaDescription());
            cellTemplateConfigList.add(cellTemplateConfig);
        }

        if (cellTemplateConfigDto.getHasVoucher() != null && cellTemplateConfigDto.getHasVoucher()) {
            CellTemplateConfig cellTemplateConfig = new CellTemplateConfig();
            cellTemplateConfig.setId(distributedIdService.nextId());
            cellTemplateConfig.setCellTemplateId(Long.parseLong(cellTemplateConfigDto.getCellTemplateId()));
            cellTemplateConfig.setReportTemplateId(Long.parseLong(cellTemplateConfigDto.getTemplateId()));
            cellTemplateConfig.setCreateBy(cellTemplateConfigDto.getCreator());
            cellTemplateConfig.setUpdateBy(cellTemplateConfigDto.getUpdater());
            cellTemplateConfig.setUpdateTime(new Date());
            cellTemplateConfig.setCreateTime(new Date());
            cellTemplateConfig.setDataSourceType(CellDataSourceType.Voucher.getCode());
            cellTemplateConfig.setVoucherKeyword(cellTemplateConfigDto.getVoucherKeyword());
            cellTemplateConfig.setAccountCodes(getJoinString(cellTemplateConfigDto.getAccountCodes()));
            cellTemplateConfigList.add(cellTemplateConfig);
        }

        if (cellTemplateConfigDto.getHasInvoice() != null && cellTemplateConfigDto.getHasInvoice()) {
            CellTemplateConfig cellTemplateConfig = new CellTemplateConfig();
            cellTemplateConfig.setId(distributedIdService.nextId());
            cellTemplateConfig.setCellTemplateId(Long.parseLong(cellTemplateConfigDto.getCellTemplateId()));
            cellTemplateConfig.setReportTemplateId(Long.parseLong(cellTemplateConfigDto.getTemplateId()));
            cellTemplateConfig.setCreateBy(cellTemplateConfigDto.getCreator());
            cellTemplateConfig.setUpdateBy(cellTemplateConfigDto.getUpdater());
            cellTemplateConfig.setUpdateTime(new Date());
            cellTemplateConfig.setCreateTime(new Date());
            cellTemplateConfig.setDataSourceType(getInvoiceType(cellTemplateConfigDto.getInvoiceType()).getCode());
            cellTemplateConfig.setInvoiceType(cellTemplateConfigDto.getInvoiceType());
            cellTemplateConfig.setInvoiceAmountType(cellTemplateConfigDto.getInvoiceAmountType());
            cellTemplateConfig.setTaxRate(getJoinString(cellTemplateConfigDto.getTaxRate()));
            cellTemplateConfig.setInvoiceCategory(getJoinString(cellTemplateConfigDto.getInvoiceCategory().stream().map(String::valueOf).collect(Collectors.toList())));
            cellTemplateConfigList.add(cellTemplateConfig);
        }

        if (cellTemplateConfigDto.getHasKeyIn() != null && cellTemplateConfigDto.getHasKeyIn()) {
            CellTemplateConfig cellTemplateConfig = new CellTemplateConfig();
            cellTemplateConfig.setId(distributedIdService.nextId());
            cellTemplateConfig.setCellTemplateId(Long.parseLong(cellTemplateConfigDto.getCellTemplateId()));
            cellTemplateConfig.setReportTemplateId(Long.parseLong(cellTemplateConfigDto.getTemplateId()));
            cellTemplateConfig.setCreateBy(cellTemplateConfigDto.getCreator());
            cellTemplateConfig.setUpdateBy(cellTemplateConfigDto.getUpdater());
            cellTemplateConfig.setUpdateTime(new Date());
            cellTemplateConfig.setCreateTime(new Date());
            cellTemplateConfig.setDataSourceType(CellDataSourceType.KeyIn.getCode());
            cellTemplateConfigList.add(cellTemplateConfig);
        }

        if (cellTemplateConfigDto.getHasModel() != null && cellTemplateConfigDto.getHasModel()) {
            CellTemplateConfig cellTemplateConfig = new CellTemplateConfig();
            cellTemplateConfig.setId(distributedIdService.nextId());
            cellTemplateConfig.setCellTemplateId(Long.parseLong(cellTemplateConfigDto.getCellTemplateId()));
            cellTemplateConfig.setReportTemplateId(Long.parseLong(cellTemplateConfigDto.getTemplateId()));
            cellTemplateConfig.setCreateBy(cellTemplateConfigDto.getCreator());
            cellTemplateConfig.setUpdateBy(cellTemplateConfigDto.getUpdater());
            cellTemplateConfig.setUpdateTime(new Date());
            cellTemplateConfig.setCreateTime(new Date());
            cellTemplateConfig.setDataSourceType(CellDataSourceType.RelatedModel.getCode());
            cellTemplateConfig.setModelIds(getJoinString(cellTemplateConfigDto.getModelIds()));
            cellTemplateConfigList.add(cellTemplateConfig);
        }

        if (cellTemplateConfigDto.getHasValidation() != null && cellTemplateConfigDto.getHasValidation()) {
            CellTemplateConfig cellTemplateConfig = new CellTemplateConfig();
            cellTemplateConfig.setId(distributedIdService.nextId());
            cellTemplateConfig.setCellTemplateId(Long.parseLong(cellTemplateConfigDto.getCellTemplateId()));
            cellTemplateConfig.setReportTemplateId(Long.parseLong(cellTemplateConfigDto.getTemplateId()));
            cellTemplateConfig.setCreateBy(cellTemplateConfigDto.getCreator());
            cellTemplateConfig.setUpdateBy(cellTemplateConfigDto.getUpdater());
            cellTemplateConfig.setUpdateTime(new Date());
            cellTemplateConfig.setCreateTime(new Date());
            cellTemplateConfig.setDataSourceType(CellDataSourceType.Validation.getCode());
            cellTemplateConfig.setValidation(cellTemplateConfigDto.getValidation());
            cellTemplateConfig.setValidationDescription(cellTemplateConfigDto.getValidationDescription());
            cellTemplateConfigList.add(cellTemplateConfig);
        }
        operationResultDto.setResult(true);
        operationResultDto.setData(cellTemplateConfigList);
        return operationResultDto;
    }

    private CellDataSourceType getInvoiceType(Integer invoiceType) {
        if (invoiceType == null) {
            return CellDataSourceType.InputInvoice;
        }

        if (invoiceType == 1) {
            return CellDataSourceType.InputInvoice;
        } else if (invoiceType == 2) {
            return CellDataSourceType.OutputInvoice;
        } else if (invoiceType == 3) {
            return CellDataSourceType.CustomInvoice;
        }

        return CellDataSourceType.InputInvoice;
    }

    private String getJoinString(List<String> array) {
        if (array != null && array.size() > 0) {
            StringBuilder sb = new StringBuilder();
            for (String s : array) {
                sb.append(s).append(",");
            }
            String tempStr = sb.toString();
            return StringUtils.removeEnd(tempStr, ",");
//            return tempStr.substring(0, tempStr.length() - 2);
        }

        return null;
    }

    private String getFormulaDataSource(String formula, List<String> keyValueConfigIds) {
        FormulaConfigExample example = new FormulaConfigExample();
        example.setOrderByClause("LENGTH(FORMULA_NAME) desc");
        List<FormulaConfig> dataSourceList = formulaConfigMapper.selectByExample(example);
        List<String> nameList = new ArrayList<>();
        FormulaHelper formulaHelper = new FormulaHelper();
//        String tmpFormula = formulaHelper.formatFormula(formula).toUpperCase();
        String tmpFormula = formula.toUpperCase();

        for (FormulaConfig dataSource : dataSourceList) {
            if (tmpFormula.contains(dataSource.getFormulaName().toUpperCase() + "(") && !nameList.contains(dataSource.getDataSourceName())) {
                nameList.add(dataSource.getDataSourceName());
            }
        }

        String keyValueMethodName = "KEYVALUE(";
        if (tmpFormula.contains(keyValueMethodName)) {
            KeyValueConfigExample keyValueConfigExample = new KeyValueConfigExample();
            keyValueConfigExample.setOrderByClause("LENGTH(KEY_CODE) desc");
            List<KeyValueConfig> keyValueList = keyValueConfigMapper.selectByExample(keyValueConfigExample);
            for (KeyValueConfig keyValueConfig : keyValueList) {
                if (tmpFormula.contains(keyValueMethodName + "\"" + keyValueConfig.getKeyCode().toUpperCase() + "\")")) {
                    if (!StringUtils.isBlank(keyValueConfig.getDataSource())) {
                        String dataSourceName = keyValueConfig.getDataSource().split("_")[1];
                        if (!nameList.contains(dataSourceName)) {
                            nameList.add(dataSourceName);
                        }
                    }

                    if (keyValueConfigIds.contains(keyValueConfig.getId())) {
                        keyValueConfigIds.add(keyValueConfig.getId());
                    }
                }
            }
        }

        if (nameList.isEmpty()) {
//            return formula;
           return "报表公式";
        } else {
            return String.join("+", nameList);
        }
    }

    private CellTemplateConfigDto getConfigDto(CellTemplate cellTemplate, List<CellTemplateConfig> configList) {
        CellTemplateConfigDto cellTemplateConfigDto = CellConfigTranslater.getConfigDto(cellTemplate, configList);
        if (cellTemplateConfigDto != null) {
            cellTemplateConfigDto.setCellTemplateId(cellTemplate.getId().toString());
            cellTemplateConfigDto.setTemplateId(cellTemplate.getReportTemplateId().toString());
            cellTemplateConfigDto.setRowIndex(cellTemplate.getRowIndex());
            cellTemplateConfigDto.setRowName(cellTemplate.getRowName());
            cellTemplateConfigDto.setColumnIndex(cellTemplate.getColumnIndex());
            cellTemplateConfigDto.setColumnName(cellTemplate.getColumnName());
            cellTemplateConfigDto.setDataType(cellTemplate.getDataType());
            cellTemplateConfigDto.setIsReadOnly(cellTemplate.getIsReadOnly());
            cellTemplateConfigDto.setFormulaDescription(cellTemplate.getComment());
            return cellTemplateConfigDto;
        }
        return null;
    }
}