package com.mstar.meds2.segment.qc.rule;

import com.morningstar.ge.util.collection.ListUtils;
import com.mstar.meds.base.dal.DALException;
import com.mstar.meds.base.util.DateFormatUtils;
import com.mstar.meds2.V2QcLog;
import com.mstar.meds2.enums.SegmentDataPointEnum;
import com.mstar.meds2.enums.SegmentQcLocationTypeEnum;
import com.mstar.meds2.model.SimpleCompanyInfo;
import com.mstar.meds2.qc.servicebase.QcRuleBase;
import com.mstar.meds2.qc.utils.V2QcLogHelper;
import com.mstar.meds2.segment.SegmentDataPoint;
import com.mstar.meds2.segment.SegmentReport;
import com.mstar.meds2.segment.SegmentValue;
import com.mstar.meds2.segment.loading.SegmentDpLoader;
import org.apache.commons.lang.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by jliang5 on 12/27 0027.
 */
public class SegmentValueCompanyTotalVsAsReportedTotal extends QcRuleBase {
    List<SegmentValue> segmentTotalAllValues ;
    @Override
    protected void doCheck() throws Exception {
        for (Integer fileId : qcData.getChangedFileIds()) {
            List<SegmentReport> segmentReports = qcData.getOneDocSegmentReportsByFileId(fileId);
            List<String> datapointQcList = new ArrayList<>();
            SimpleCompanyInfo companyInfo = qcData.getCompanyInfo();
            if(ListUtils.isNotEmpty(segmentReports)){
                for (SegmentReport eachReport : segmentReports) {
                    if(docHasRuledp(companyInfo,fileId,eachReport,datapointQcList)){
                        BigDecimal companyTotal  = getCompanyTotal(eachReport);
                        BigDecimal segmentTotal = calculateValue(segmentTotalAllValues);
                        if(companyTotal.compareTo(BigDecimal.ZERO) != 0 && segmentTotal.compareTo(BigDecimal.ZERO) != 0){
                            if(companyTotal.subtract(segmentTotal).divide(companyTotal,2,BigDecimal.ROUND_HALF_UP).abs().compareTo(new BigDecimal(0.1)) == 1){
                                this.logInfo(fileId,eachReport,companyTotal,segmentTotal,datapointQcList);
                            }
                        }else {
                            if(companyTotal.subtract(segmentTotal).abs().compareTo(new BigDecimal(0.1)) == 1){
                                this.logInfo(fileId,eachReport,companyTotal,segmentTotal,datapointQcList);
                            }
                        }
                    }
                }
            }
        }
    }

    private BigDecimal getCompanyTotal(SegmentReport eachReport) {
        BigDecimal companyTotal = null;
        if(this.getLogicExpression().equalsIgnoreCase(SegmentDataPointEnum.Total_Revenue.getName())){
            companyTotal = eachReport.getTotalRevenue();
        }else if(this.getLogicExpression().equalsIgnoreCase(SegmentDataPointEnum.Operating_Income.getName())){
            companyTotal = eachReport.getTotalOperatingIncome();
        }else if(this.getLogicExpression().equalsIgnoreCase(SegmentDataPointEnum.Net_Income.getName())){
            companyTotal = eachReport.getTotalNetIncome();
        }else {
            companyTotal = eachReport.getTotalAssets();
        }
        if(null == companyTotal){
            companyTotal = BigDecimal.ZERO;
        }
        return companyTotal;
    }

    private boolean docHasRuledp(SimpleCompanyInfo companyInfo, Integer fileId, SegmentReport report, List<String> datapointQcList) throws DALException {
        boolean hasRuleDp = false;
        if(this.getLogicExpression().trim().equals("Total Asset")){
            this.setLogicExpression("Total Assets");
        }
        List<SegmentValue> fatherDatapointAllValues = qcData.getOneDatapointAllValues(report.getReportId(), SegmentDataPointEnum.getValueByName(this.getLogicExpression().trim()));
        if(ListUtils.isNotEmpty(fatherDatapointAllValues)) {
            hasRuleDp = true;
            datapointQcList.add(SegmentDataPointEnum.getValueByName(this.getLogicExpression().trim()));
            segmentTotalAllValues = fatherDatapointAllValues;
        }else{
            List<SegmentValue> childrenDatapointAllValues = getRollUpValueList(companyInfo, fileId, report,datapointQcList);
            if(ListUtils.isNotEmpty(childrenDatapointAllValues)){
                hasRuleDp = true;
                segmentTotalAllValues = childrenDatapointAllValues;
            }
        }
        return hasRuleDp;
    }

    private List<SegmentValue> getRollUpValueList(SimpleCompanyInfo companyInfo, Integer fileId, SegmentReport report,List<String> datapointQcList) throws DALException {
        List<SegmentValue> rollUpValueList = new ArrayList<>();
        List<SegmentDataPoint> rollUpDpChildren = getRollUpDpChildren(companyInfo);
        if(ListUtils.isNotEmpty(rollUpDpChildren) && !rollUpDpChildren.get(0).getDataPointId().equals(SegmentDataPointEnum.Non_Current_Assets.getValue())){
            for (SegmentDataPoint eachChildDp : rollUpDpChildren) {
                datapointQcList.add(eachChildDp.getDataPointId());
                rollUpValueList.addAll(qcData.getOneDatapointAllValues(report.getReportId(), eachChildDp.getDataPointId()));
            }
        }
        return rollUpValueList;
    }

    private List<SegmentDataPoint> getRollUpDpChildren(SimpleCompanyInfo companyInfo) {
        List<SegmentDataPoint> rollUpChildren = new ArrayList<>();
        List<SegmentDataPoint> dataPointList = SegmentDpLoader.getInstance().getSegmentDpByFileSourceAndIndustryCode(companyInfo.getFileSource(), companyInfo.getIndustryTemplateCode());
        for (SegmentDataPoint eachDp : dataPointList) {
            if(eachDp.getRollUpTo() != null
                    && eachDp.getRollUpTo().equalsIgnoreCase(SegmentDataPointEnum.getValueByName(this.getLogicExpression().trim()))
                    && !eachDp.getDataPointId().equalsIgnoreCase(eachDp.getRollUpTo())){
                rollUpChildren.add(eachDp);
            }
        }
        return rollUpChildren;
    }

    private BigDecimal calculateValue(List<SegmentValue> segmentTotalValueList) {
        BigDecimal result = BigDecimal.ZERO;
        if(ListUtils.isNotEmpty(segmentTotalValueList)){
            for (SegmentValue eachValue : segmentTotalValueList) {
                BigDecimal value = eachValue.getValue();
                if(value != null){
                    result = result.add(value);
                }
            }
        }
        return result;
    }

    private void logInfo(Integer fileId, SegmentReport report, BigDecimal value1, BigDecimal value2,List<String> datapointQcList){
        String showInfo = this.getShowInfo(fileId,report,value1,value2);
        StringBuilder sb = new StringBuilder();
        sb.append("header_"+SegmentQcLocationTypeEnum.DATALOCATION.getDescription() + "_" + report.getReportId() + "_" + replaceBlankSpace(this.getLogicExpression().trim().toLowerCase()));
        for (String eachDpId : datapointQcList) {
            sb.append("||").append("values_"+SegmentQcLocationTypeEnum.AREALOCATION.getDescription() + "_" + report.getReportId() + "_" + eachDpId);
        }
        V2QcLog log = V2QcLogHelper.generateSegmentQcLog(ruleId, qcData.getCompanyId(), qcData.getTableType(), fileId, showInfo, sb.toString());
        this.addLog(log);
    }
    private String getShowInfo(Integer fileId,SegmentReport report,BigDecimal value1,BigDecimal value2){
        StringBuilder sb = new StringBuilder();
        sb.append("DocId: " +fileId+ ",PED: " + DateFormatUtils.format(report.getPeriodEndDate(),"yyyy-MM-dd") + ",CompanyLevelTotal: " + value1);
        sb.append(" || ");
        sb.append("DocId: " +fileId+ ",PED: " + DateFormatUtils.format(report.getPeriodEndDate(),"yyyy-MM-dd") + ",SegmentTotal: " + value2);
        return sb.toString();
    }

    private String replaceBlankSpace(String str) {
        if (StringUtils.isBlank(str)) {
            return str;
        }

        return str.replaceAll("\\s|\t|&nbsp;|_", "");
    }
}