package controllers.strategytest;

import components.FloatStatRow;
import components.NumberStatRow;
import interfaces.strategytest.BettingStrategyInterface;
import javafx.scene.layout.VBox;
import objects.SoccerMatch;
import objects.SoccerMatchAnalysis;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>There are of course numerous ideas, concepts and formulas that can help you calculate the ideal stake on a bet.
 * One of them is the Kelly formula. </p>
 *
 * <p>Of course, this is no guarantee that you will always bet correctly and the assessment of how likely the outcome of a game is, does still remain up to you.
 But the Kelly formula can help you choose the size of your bet.</p>
 *
 * <p>This is how the Kelly formula works</p>
 *
 * <p>You choose a game or an event and rate the outcome as a percentage
 * Example: Austria defeats Germany – you rate this outcome with a probability of 20%
 * Now, you are looking for an odd for this event that seems fair to you
 * Then, you put the probability and the odds in the Kelly formula and get a value from it
 * Let us take as an example the 20% probability of winning with odds of @ 5.50.</p>
 * <p>First we do the math, where the probability of 100% is 1:</p>
 *
 * <p>Kelly value calculation sportsbetting
 * Value calculation after Kelly
 * Now we can continue to calculate and find the best possible stake for this bet.
 * </p>
 * <p>The formula used to choose a reasonable stake looks like this:
 *
 * Percentage of bankroll to be set = value / (odds – 1)
 *</p>
 * <p>In our case this means:
 *
 * Kelly bankroll calculation sportsbetting
 * Bankroll calculation after Kelly
 * The Kelly Formula hereby recommends that, given the probability that you have determined yourself and the odds you have chosen, you should bet 2.
 * 22% of your bankroll on this event.</p>
 *
 * <p>Now, of course, the use of this formula also depends heavily on your assessment of the probability.
 * And if you consider a game outcome to be very likely and thus increase the value considerably, then it can happen that you get 30% or even more of your bankroll as a result.
 * Of course, caution is advised here because your bankroll can slide down very quickly this way.</p>
 *
 * <p>It is also possible that you will get a negative result when calculating the first value.
 * This happens if you bet too low with an expected probability of winning on an event with too low odds.
 * The result is that your value is negative, which means nothing else than: if you are unsure about this, then this bet just doesn’t pay off …
 * </p>
 */
public class KellyFormulaStrategy extends VBox implements BettingStrategyInterface {

    public static final String NAME = "Kelly Formula";
    List<SoccerMatch> matches;
    private float startingBank = 1000f;
    private FloatStatRow wonLossBankStatRow;
    private NumberStatRow sequencesPlayedStatRow;

    private NumberStatRow sequencesWonStatRow;

    public KellyFormulaStrategy() {
        super();
        buildSettingsGuiPanel();
        buildStatGuiPanel();
        buildMatchSummaryPanel();
    }

    @Override
    public void setMatches(List<SoccerMatch> matches) {
        this.matches = matches;
    }

    @Override
    public void buildSettingsGuiPanel() {
        // Empty for now
    }

    @Override
    public void buildStatGuiPanel() {
        sequencesPlayedStatRow = new NumberStatRow("Number of matches played", 0);
        sequencesWonStatRow = new NumberStatRow("Number of matches won", 0);

        wonLossBankStatRow = new FloatStatRow("Amount won or lost", 0f);

        this.getChildren().add(sequencesPlayedStatRow);
        this.getChildren().add(sequencesWonStatRow);
        this.getChildren().add(wonLossBankStatRow);
    }

    @Override
    public void buildMatchSummaryPanel() {
        // Empty for now
    }

    @Override
    public void runTest() {
        for (SoccerMatch match : matches) {
            List<SoccerMatchAnalysis> todaysMatches = filterTodaysMatches(matches, match).stream().map(SoccerMatchAnalysis::new).collect(Collectors.toList());
            todaysMatches.forEach(SoccerMatchAnalysis::calculateWinPercentages);
            //todaysMatches= sortMatchesOnBetPotential(todaysMatches);
            String bet = shouldBetOn(match);
            if (bet != null) {
                // TODO: Implement betting
            }
        }

    }

    @Override
    public String shouldBetOn(SoccerMatch match) {
        return "1X2";
    }

    @Override
    public List<?> sortMatchesOnBetPotential(List<SoccerMatch> matches) {
        return null;
    }

//    @Override
//    public List<SoccerMatchAnalysis> sortMatchesOnBetPotential(List<SoccerMatchAnalysis> matches) {
//
//        matches.sort((SoccerMatchAnalysis match1, SoccerMatchAnalysis match2) -> {
//            KellyFormulaBet kellyFormulaBet1 = new KellyFormulaBet(match1);
//            KellyFormulaBet kellyFormulaBet2 = new KellyFormulaBet(match2);
//            kellyFormulaBet1.compareTo(kellyFormulaBet2);
//
//            return
//        }
//        return matches;
//    }


    public void reset() {
        sequencesPlayedStatRow.getChildren().clear();
        sequencesWonStatRow.getChildren().clear();
        wonLossBankStatRow.getChildren().clear();

        buildStatGuiPanel();
        buildMatchSummaryPanel();
    }

    private class KellyFormulaBet {

        private String toBetOn;
        private float diffOdds1Calculated;
        private float diffOddsXCalculated;
        private float diffOdds2Calculated;

        public KellyFormulaBet(SoccerMatchAnalysis match) {
            bestBetValue(match);
            setDiffOdds1Calculated(match);
            setDiffOddsXCalculated(match);
            setDiffOdds2Calculated(match);
        }
        private void bestBetValue(SoccerMatchAnalysis match) {
            float diffOdds1Calculated = getDiffOdds1Calculated(match);
            float diffOddsXCalculated = getDiffOddsXCalculated(match);
            float diffOdds2Calculated = getDiffOdds2Calculated(match);

            if (diffOdds1Calculated > diffOddsXCalculated && diffOdds1Calculated > diffOdds2Calculated) {
                toBetOn =  "1";
            } else if (diffOddsXCalculated > diffOdds1Calculated && diffOddsXCalculated > diffOdds2Calculated) {
                toBetOn = "X";
            } else if (diffOdds2Calculated > diffOdds1Calculated && diffOdds2Calculated > diffOddsXCalculated) {
                toBetOn = "2";
            }
        }

        private float getDiffOdds1Calculated(SoccerMatchAnalysis match) {
            return diffOdds1Calculated;
        }

        private float getDiffOddsXCalculated(SoccerMatchAnalysis match) {
            return diffOddsXCalculated;
        }

        private float getDiffOdds2Calculated(SoccerMatchAnalysis match) {
            return diffOdds2Calculated;
        }

        private void setDiffOdds1Calculated(SoccerMatchAnalysis match) {
            float winOddsCalculated = convertPercentageToOdds(match.getCalculatedPercentages().getHomeWinPercentage());
            diffOdds1Calculated = match.getOdds1() - winOddsCalculated;
        }

        private void setDiffOddsXCalculated(SoccerMatchAnalysis match) {
            float drawOddsCalculated = convertPercentageToOdds(match.getCalculatedPercentages().getDrawPercentage());
            diffOddsXCalculated = match.getOddsX() - drawOddsCalculated;
        }

        private void setDiffOdds2Calculated(SoccerMatchAnalysis match) {
            float loseOddsCalculated = convertPercentageToOdds(match.getCalculatedPercentages().getAwayWinPercentage());
            diffOdds2Calculated = match.getOdds2() - loseOddsCalculated;
        }

        public void compareTo(KellyFormulaBet kellyFormulaBet2) {
            
        }
    }

}
