package com.bailuntec.service.impl;

import com.bailuntec.domain.entity.DcAutoSalesForecastConfig;
import com.bailuntec.domain.entity.DcAutoSalesForecastStageConfig;
import com.bailuntec.domain.entity.DcAutoTurnover;
import com.bailuntec.domain.entity.DcBaseOmsSku;
import com.bailuntec.mapper.DcAutoSalesForecastConfigMapper;
import com.bailuntec.mapper.DcAutoSalesForecastStageConfigMapper;
import com.bailuntec.mapper.DcBaseOmsSkuMapper;
import com.bailuntec.service.AutoTurnoverService;
import com.bailuntec.utils.SessionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSession;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

import static java.time.temporal.ChronoUnit.DAYS;

/**
 * <p>
 *
 * </p>
 *
 * @author robbendev
 * @since 2020/8/13 2:09 下午
 */
@Slf4j
public class AutoTurnoverServiceImpl implements AutoTurnoverService {


    @Override
    public List<BigDecimal> getAutoTurnoverSaleDetails(DcAutoTurnover dcAutoTurnover, int turnoverDays, int autoForecastDay) {

        try (SqlSession session = SessionUtil.getFactory().openSession(true)) {

            Queue<BigDecimal> forecastSalesDetails = new LinkedList<>();


            for (int j = 0; j < new BigDecimal(autoForecastDay).divide(new BigDecimal(turnoverDays), 0, BigDecimal.ROUND_UP).intValue(); j++) {

                DcAutoSalesForecastStageConfigMapper dcAutoSalesForecastStageConfigMapper = session.getMapper(DcAutoSalesForecastStageConfigMapper.class);
                DcBaseOmsSkuMapper dcBaseOmsSkuMapper = session.getMapper(DcBaseOmsSkuMapper.class);
                DcAutoSalesForecastConfigMapper dcAutoSalesForecastConfigMapper = session.getMapper(DcAutoSalesForecastConfigMapper.class);

                DcBaseOmsSku orderFirstCreateTime = dcAutoSalesForecastStageConfigMapper.firsOrder(dcAutoTurnover.getBailunSku(), dcAutoTurnover.getWarehouseCode());

                Long day = Optional.ofNullable(orderFirstCreateTime).map(item -> DAYS.between(item.getCreateTime().toLocalDate(), LocalDate.now())).orElse(null);

                BigDecimal avgOrderCount30 = dcAutoSalesForecastStageConfigMapper.avgOrderCount(dcAutoTurnover.getBailunSku(), dcAutoTurnover.getWarehouseCode(), 30);
                BigDecimal avgOrderCount14 = dcAutoSalesForecastStageConfigMapper.avgOrderCount(dcAutoTurnover.getBailunSku(), dcAutoTurnover.getWarehouseCode(), 14);
                BigDecimal avgOrderCount7 = dcAutoSalesForecastStageConfigMapper.avgOrderCount(dcAutoTurnover.getBailunSku(), dcAutoTurnover.getWarehouseCode(), 7);

                //命中的预测规则
                DcAutoSalesForecastStageConfig dcAutoSalesForecastStageConfig = dcAutoSalesForecastStageConfigMapper
                        .selectMatchStage(dcAutoTurnover.getBailunSku(), dcAutoTurnover.getWarehouseCode(), day,
                                avgOrderCount30, avgOrderCount14, avgOrderCount7);

                //周转天数
                //每个时间段的销量预测是dcAutoSalesForecastStageConfig对应时间段的三个参数对应的过去时间段的销量的加权平均*/

                //今天0点
                LocalDateTime midNight = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
                String bailunSku = dcAutoTurnover.getBailunSku();
                String warehouseCode = dcAutoTurnover.getWarehouseCode();


                if (dcAutoSalesForecastStageConfig != null) {
                    DcAutoSalesForecastConfig dcAutoSalesForecastConfig = dcAutoSalesForecastConfigMapper.selectById(dcAutoSalesForecastStageConfig.getConfigId());

                    dcAutoTurnover.setDcAutoSalesForecastConfigId(dcAutoSalesForecastStageConfig.getConfigId());
                    dcAutoTurnover.setDcAutoSalesForecastStageConfigId(dcAutoSalesForecastStageConfig.getId());
                    dcAutoTurnover.setDcAutoSalesForecastTitle(dcAutoSalesForecastConfig.getTitle());

                    dcAutoTurnover.setFirstOrderDate(Optional.ofNullable(orderFirstCreateTime).map(DcBaseOmsSku::getCreateTime).orElse(null));
                    dcAutoTurnover.setFirstOrderBailunOrderId(Optional.ofNullable(orderFirstCreateTime).map(DcBaseOmsSku::getBailunOrderId).orElse(null));
                    dcAutoTurnover.setOrdersAvg(avgOrderCount30);

                    log.info("匹配到一条规则 id：{}", dcAutoSalesForecastStageConfig.getConfigId());

                    int duration1 = BigDecimal.valueOf(turnoverDays).multiply(dcAutoSalesForecastStageConfig.getOneRatio()).intValue();
                    int duration2 = BigDecimal.valueOf(turnoverDays).multiply(dcAutoSalesForecastStageConfig.getTwoRatio()).intValue();
                    int duration3 = turnoverDays - duration1 - duration2;


                    int oneN1 = dcAutoSalesForecastStageConfig.getOneN1().intValue();
                    int oneN3 = dcAutoSalesForecastStageConfig.getOneN3().intValue();
                    int oneN5 = dcAutoSalesForecastStageConfig.getOneN5().intValue();
                    int twoN1 = dcAutoSalesForecastStageConfig.getTwoN1().intValue();
                    int twoN3 = dcAutoSalesForecastStageConfig.getTwoN3().intValue();
                    int twoN5 = dcAutoSalesForecastStageConfig.getTwoN5().intValue();
                    int threeN1 = dcAutoSalesForecastStageConfig.getThreeN1().intValue();
                    int threeN3 = dcAutoSalesForecastStageConfig.getThreeN3().intValue();
                    int threeN5 = dcAutoSalesForecastStageConfig.getThreeN5().intValue();

                    /*第一部分预测*/
                    BigDecimal duration1ForecastSellerNum = Optional.ofNullable(dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getOneN1().intValue()), midNight, bailunSku, warehouseCode, oneN1 == 0 ? 1 : oneN1, dcAutoSalesForecastConfig.getDataSourcePlatform())).orElse(BigDecimal.ZERO)
                            .multiply(dcAutoSalesForecastStageConfig.getOneN2())
                            .add(Optional.ofNullable(dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getOneN3().intValue()), midNight, bailunSku, warehouseCode, oneN3 == 0 ? 1 : oneN3, dcAutoSalesForecastConfig.getDataSourcePlatform())).orElse(BigDecimal.ZERO)
                                    .multiply(dcAutoSalesForecastStageConfig.getOneN4()))
                            .add(dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getOneN5().intValue()), midNight, bailunSku, warehouseCode, oneN5 == 0 ? 1 : oneN5, dcAutoSalesForecastConfig.getDataSourcePlatform())
                                    .multiply(dcAutoSalesForecastStageConfig.getOneN6()));

                    for (int i = 0; i < duration1; i++) {
                        if (autoForecastDay >= forecastSalesDetails.size()) {
                            forecastSalesDetails.offer(duration1ForecastSellerNum);
                        }
                    }

                    /*第二部分预测*/
                    BigDecimal duration2ForecastSellerNum = dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getTwoN1().intValue()), midNight, bailunSku, warehouseCode, twoN1 == 0 ? 1 : twoN1, dcAutoSalesForecastConfig.getDataSourcePlatform())
                            .multiply(dcAutoSalesForecastStageConfig.getTwoN2())
                            .add(dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getTwoN3().intValue()), midNight, bailunSku, warehouseCode, twoN3 == 0 ? 1 : twoN3, dcAutoSalesForecastConfig.getDataSourcePlatform())
                                    .multiply(dcAutoSalesForecastStageConfig.getTwoN4()))
                            .add(dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getTwoN5().intValue()), midNight, bailunSku, warehouseCode, twoN5 == 0 ? 1 : twoN5, dcAutoSalesForecastConfig.getDataSourcePlatform())
                                    .multiply(dcAutoSalesForecastStageConfig.getTwoN6()));

                    for (int i = 0; i < duration2; i++) {
                        if (autoForecastDay >= forecastSalesDetails.size()) {
                            forecastSalesDetails.offer(duration2ForecastSellerNum);
                        }
                    }


                    /*第三部分预测*/
                    BigDecimal duration3ForecastSellerNum = dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getThreeN1().intValue()), midNight, bailunSku, warehouseCode, threeN1 == 0 ? 1 : threeN1, dcAutoSalesForecastConfig.getDataSourcePlatform())
                            .multiply(dcAutoSalesForecastStageConfig.getThreeN2())
                            .add(dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getThreeN3().intValue()), midNight, bailunSku, warehouseCode, threeN3 == 0 ? 1 : threeN3, dcAutoSalesForecastConfig.getDataSourcePlatform())
                                    .multiply(dcAutoSalesForecastStageConfig.getThreeN4()))
                            .add(dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getThreeN5().intValue()), midNight, bailunSku, warehouseCode, threeN5 == 0 ? 1 : threeN5, dcAutoSalesForecastConfig.getDataSourcePlatform())
                                    .multiply(dcAutoSalesForecastStageConfig.getThreeN6()));

                    for (int i = 0; i < duration3; i++) {
                        if (autoForecastDay >= forecastSalesDetails.size()) {
                            forecastSalesDetails.offer(duration3ForecastSellerNum);
                        }
                    }


                } else {
                    log.info("没有匹配销量预测规则，采用平均销量");

                    dcAutoTurnover.setDcAutoSalesForecastConfigId(-1);
                    dcAutoTurnover.setDcAutoSalesForecastStageConfigId(-1);
                    dcAutoTurnover.setDcAutoSalesForecastTitle("");

                    for (int i = 0; i < turnoverDays; i++) {
                        if (autoForecastDay >= forecastSalesDetails.size()) {
                            forecastSalesDetails.offer(dcAutoTurnover.getDailyWeightedSales() == null ? BigDecimal.ZERO : dcAutoTurnover.getDailyWeightedSales());
                        }
                    }
                }
            }
            return new ArrayList<>(forecastSalesDetails);
        }
    }


    @Override
    public List<String> getAutoTurnoverSaleDetailsFormula(DcAutoTurnover dcAutoTurnover, int turnoverDays, int autoForecastDay) {

        SqlSession session = SessionUtil.getFactory().openSession(true);
        try {
            //销量公式
            Queue<String> forecastSalesDetailsFormula = new LinkedList<>();

            for (int j = 0; j < new BigDecimal(autoForecastDay).divide(new BigDecimal(turnoverDays), 0, BigDecimal.ROUND_UP).intValue(); j++) {

                DcAutoSalesForecastStageConfigMapper dcAutoSalesForecastStageConfigMapper = session.getMapper(DcAutoSalesForecastStageConfigMapper.class);
                DcBaseOmsSkuMapper dcBaseOmsSkuMapper = session.getMapper(DcBaseOmsSkuMapper.class);
                DcAutoSalesForecastConfigMapper dcAutoSalesForecastConfigMapper = session.getMapper(DcAutoSalesForecastConfigMapper.class);

                DcBaseOmsSku orderFirstCreateTime = dcAutoSalesForecastStageConfigMapper.firsOrder(dcAutoTurnover.getBailunSku(), dcAutoTurnover.getWarehouseCode());
                Long day = Optional.ofNullable(orderFirstCreateTime).map(item -> DAYS.between(item.getCreateTime().toLocalDate(), LocalDate.now())).orElse(null);

                BigDecimal avgOrderCount30 = dcAutoSalesForecastStageConfigMapper.avgOrderCount(dcAutoTurnover.getBailunSku(), dcAutoTurnover.getWarehouseCode(), 30);
                BigDecimal avgOrderCount14 = dcAutoSalesForecastStageConfigMapper.avgOrderCount(dcAutoTurnover.getBailunSku(), dcAutoTurnover.getWarehouseCode(), 14);
                BigDecimal avgOrderCount7 = dcAutoSalesForecastStageConfigMapper.avgOrderCount(dcAutoTurnover.getBailunSku(), dcAutoTurnover.getWarehouseCode(), 7);

                //命中的预测规则
                DcAutoSalesForecastStageConfig dcAutoSalesForecastStageConfig = dcAutoSalesForecastStageConfigMapper
                        .selectMatchStage(dcAutoTurnover.getBailunSku(), dcAutoTurnover.getWarehouseCode(), day
                                , avgOrderCount30, avgOrderCount14, avgOrderCount7);

                //今天0点
                LocalDateTime midNight = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
                String bailunSku = dcAutoTurnover.getBailunSku();
                String warehouseCode = dcAutoTurnover.getWarehouseCode();


                if (dcAutoSalesForecastStageConfig != null) {

                    log.info("匹配到一条规则 id：{}", dcAutoSalesForecastStageConfig.getConfigId());
                    DcAutoSalesForecastConfig dcAutoSalesForecastConfig = dcAutoSalesForecastConfigMapper.selectById(dcAutoSalesForecastStageConfig.getConfigId());

                    int duration1 = BigDecimal.valueOf(turnoverDays).multiply(dcAutoSalesForecastStageConfig.getOneRatio()).intValue();
                    int duration2 = BigDecimal.valueOf(turnoverDays).multiply(dcAutoSalesForecastStageConfig.getTwoRatio()).intValue();
                    int duration3 = turnoverDays - duration1 - duration2;


                    int oneN1 = dcAutoSalesForecastStageConfig.getOneN1().intValue();
                    int oneN3 = dcAutoSalesForecastStageConfig.getOneN3().intValue();
                    int oneN5 = dcAutoSalesForecastStageConfig.getOneN5().intValue();
                    int twoN1 = dcAutoSalesForecastStageConfig.getTwoN1().intValue();
                    int twoN3 = dcAutoSalesForecastStageConfig.getTwoN3().intValue();
                    int twoN5 = dcAutoSalesForecastStageConfig.getTwoN5().intValue();
                    int threeN1 = dcAutoSalesForecastStageConfig.getThreeN1().intValue();
                    int threeN3 = dcAutoSalesForecastStageConfig.getThreeN3().intValue();
                    int threeN5 = dcAutoSalesForecastStageConfig.getThreeN5().intValue();


                    for (int i = 0; i < duration1; i++) {
                        if (autoForecastDay >= forecastSalesDetailsFormula.size()) {
                            forecastSalesDetailsFormula.offer("(" + dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getOneN1().intValue()), midNight, bailunSku, warehouseCode, oneN1 == 0 ? 1 : oneN1, dcAutoSalesForecastConfig.getDataSourcePlatform()).setScale(2, BigDecimal.ROUND_HALF_UP) + "*" + dcAutoSalesForecastStageConfig.getOneN2() + ")"
                                    + "+"
                                    + "（" + Optional.ofNullable(dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getOneN3().intValue()), midNight, bailunSku, warehouseCode, oneN3 == 0 ? 1 : oneN3, dcAutoSalesForecastConfig.getDataSourcePlatform())).orElse(BigDecimal.ZERO).setScale(2, BigDecimal.ROUND_HALF_UP) + "*" + dcAutoSalesForecastStageConfig.getOneN4() + "）"
                                    + "+"
                                    + "（" + Optional.ofNullable(dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getOneN5().intValue()), midNight, bailunSku, warehouseCode, oneN5 == 0 ? 1 : oneN5, dcAutoSalesForecastConfig.getDataSourcePlatform())).orElse(BigDecimal.ZERO).setScale(2, BigDecimal.ROUND_HALF_UP) + "*" + dcAutoSalesForecastStageConfig.getOneN6() + "）");
                        }
                    }

                    /*第二部分预测*/
                    for (int i = 0; i < duration2; i++) {
                        if (autoForecastDay >= forecastSalesDetailsFormula.size()) {

                            forecastSalesDetailsFormula.offer("(" + dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getTwoN1().intValue()), midNight, bailunSku, warehouseCode, twoN1 == 0 ? 1 : twoN1, dcAutoSalesForecastConfig.getDataSourcePlatform()).setScale(2, BigDecimal.ROUND_HALF_UP) + "*" + dcAutoSalesForecastStageConfig.getTwoN2() + ")"
                                    + "+"
                                    + "（" + Optional.ofNullable(dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getTwoN3().intValue()), midNight, bailunSku, warehouseCode, twoN3 == 0 ? 1 : twoN3, dcAutoSalesForecastConfig.getDataSourcePlatform())).orElse(BigDecimal.ZERO).setScale(2, BigDecimal.ROUND_HALF_UP) + "*" + dcAutoSalesForecastStageConfig.getTwoN4() + "）"
                                    + "+"
                                    + "（" + Optional.ofNullable(dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getTwoN5().intValue()), midNight, bailunSku, warehouseCode, twoN5 == 0 ? 1 : twoN5, dcAutoSalesForecastConfig.getDataSourcePlatform())).orElse(BigDecimal.ZERO).setScale(2, BigDecimal.ROUND_HALF_UP) + "*" + dcAutoSalesForecastStageConfig.getTwoN6() + "）");
                        }
                    }


                    /*第三部分预测*/
                    for (int i = 0; i < duration3; i++) {
                        if (autoForecastDay >= forecastSalesDetailsFormula.size()) {

                            forecastSalesDetailsFormula.offer("(" + dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getThreeN1().intValue()), midNight, bailunSku, warehouseCode, threeN1 == 0 ? 1 : threeN1, dcAutoSalesForecastConfig.getDataSourcePlatform()).setScale(2, BigDecimal.ROUND_HALF_UP) + "*" + dcAutoSalesForecastStageConfig.getThreeN2() + ")"
                                    + "+"
                                    + "（" + Optional.ofNullable(dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getThreeN3().intValue()), midNight, bailunSku, warehouseCode, threeN3 == 0 ? 1 : threeN3, dcAutoSalesForecastConfig.getDataSourcePlatform())).orElse(BigDecimal.ZERO).setScale(2, BigDecimal.ROUND_HALF_UP) + "*" + dcAutoSalesForecastStageConfig.getThreeN4() + "）"
                                    + "+"
                                    + "（" + Optional.ofNullable(dcBaseOmsSkuMapper.omsSkuSellerCount(midNight.minusDays(dcAutoSalesForecastStageConfig.getThreeN5().intValue()), midNight, bailunSku, warehouseCode, threeN5 == 0 ? 1 : threeN5, dcAutoSalesForecastConfig.getDataSourcePlatform())).orElse(BigDecimal.ZERO).setScale(2, BigDecimal.ROUND_HALF_UP) + "*" + dcAutoSalesForecastStageConfig.getThreeN6() + "）");
                        }
                    }

                } else {
                    for (int i = 0; i < turnoverDays; i++) {
                        if (autoForecastDay >= forecastSalesDetailsFormula.size()) {
                            forecastSalesDetailsFormula.add("");
                        }
                    }
                }
            }
            return new ArrayList<>(forecastSalesDetailsFormula);

        } finally {
            session.close();
        }
    }


}
