package com.sldlt.navps.service.impl;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import org.springframework.data.util.Pair;

import com.sldlt.navps.dto.PredictionResultsDto;

public abstract class AbstractRandomSplitNonlinearRegressionNAVPSPredictorServiceImpl
    extends AbstractNonlinearRegressionNAVPSPredictorServiceImpl {

    protected AbstractRandomSplitNonlinearRegressionNAVPSPredictorServiceImpl() {
        super();
    }

    @Override
    public String getType() {
        return "Random Split Nonlinear Regression " + getRangeType();
    }

    @Override
    public PredictionResultsDto predict(final String fund, final List<Integer> daysAdvance) {
        final List<Pair<BigDecimal, BigDecimal>> navpsData = fetchNavpsData(fund, getMaxRange());
        final List<List<Pair<BigDecimal, BigDecimal>>> splitNavpsData = splitNavpsData(navpsData, 4, 0.5);

        final List<PredictionResultsDto> splitResults = splitNavpsData.stream().map(this::makeParameters).map(parameters -> {
            final PredictionResultsDto results = new PredictionResultsDto();
            results.setPredictions(daysAdvance.stream().map(days -> makePrediction(parameters, days)).toList());
            results.setParameters(convertParameters(parameters));
            return results;
        }).toList();

        final PredictionResultsDto finalResults = new PredictionResultsDto();
        finalResults.setPredictions(daysAdvance.stream().map(day -> BigDecimal.ZERO).toList());
        finalResults.setParameters(new HashMap<>());
        for (int i = 0; i < splitResults.size(); i++) {
            final int currentIndex = i;
            final List<BigDecimal> splitPredictions = splitResults.get(i).getPredictions();
            for (int j = 0; j < daysAdvance.size(); j++) {
                finalResults.getPredictions().set(j, finalResults.getPredictions().get(j).add(splitPredictions.get(j)));
            }
            splitResults.get(i).getParameters().entrySet().stream()
                .forEach(entry -> finalResults.getParameters().put(entry.getKey() + "_" + currentIndex, entry.getValue()));
        }
        for (int i = 0; i < daysAdvance.size(); i++) {
            finalResults.getPredictions().set(i, finalResults.getPredictions().get(i).divide(BigDecimal.valueOf(splitResults.size())));
        }

        return finalResults;

    }

    private List<List<Pair<BigDecimal, BigDecimal>>> splitNavpsData(final List<Pair<BigDecimal, BigDecimal>> navpsData, final int numSplit,
        final double includeChance) {
        final List<List<Pair<BigDecimal, BigDecimal>>> splitNavps = new LinkedList<>();
        for (int i = 0; i < numSplit; i++) {
            splitNavps.add(navpsData.stream().filter(value -> Math.random() < includeChance).toList());
        }
        return splitNavps;
    }

    @Override
    protected abstract String getRangeType();

    @Override
    protected abstract LocalDate getMaxRange();

}

@@ -89,16 +89,74 @@
 alDate;%0A
+import java.util.ArrayList;%0Aimport java.util.Collections;%0A
 import j
@@ -1443,24 +1443,79 @@
 .toList();%0A%0A
+        final int numPredictions = daysAdvance.size();%0A
         fina
@@ -1620,39 +1620,108 @@
 ons(
-daysAdvance.stream().map(day -%3E
+new ArrayList%3C%3E());%0A        finalResults.getPredictions().addAll(Collections.nCopies(numPredictions,
  Big
@@ -1733,25 +1733,16 @@
 al.ZERO)
-.toList()
 );%0A     
@@ -1785,24 +1785,25 @@
 shMap%3C%3E());%0A
+%0A
         for 
@@ -2010,34 +2010,30 @@
  0; j %3C 
-daysAdvance.size()
+numPredictions
 ; j++) %7B
@@ -2398,34 +2398,30 @@
  0; i %3C 
-daysAdvance.size()
+numPredictions
 ; i++) %7B

fix list error