package tests.objects;

import java.util.HashMap;
import java.util.Map;

public class XBestGamesWinPercentageStatistics {


    Map<Integer, Map<Integer,WinDrawLoss>> homeWinLossRatioMap = new HashMap<>();
    Map<Integer, Map<Integer,WinDrawLoss>> awayWinLossRatioMap = new HashMap<>();

    Map<Integer, Map<Integer,WinDrawLoss>> homeWinLossRatioHomeAndAwayMap = new HashMap<>();
    Map<Integer, Map<Integer,WinDrawLoss>>  awayWinLossRatioHomeAndAwayMap = new HashMap<>();

    Map<Integer, Map<Integer,WinDrawLoss>>  homeScoringTotal = new HashMap<>();
    Map<Integer, Map<Integer,WinDrawLoss>>  awayScoringTotal = new HashMap<>();

    Map<Integer, Map<Integer,WinDrawLoss>>  scoringDiffLastGamesMap = new HashMap<>();

    public static final XBestGamesWinPercentageStatistics INSTANCE = new XBestGamesWinPercentageStatistics();

    private XBestGamesWinPercentageStatistics() { }

    public void addHomeWinLossRatio(int lookback, int value, boolean win, boolean draw, boolean loss) {
        Map<Integer,WinDrawLoss> winDrawLossValueMap = homeWinLossRatioMap.getOrDefault(lookback, new HashMap<>());
        WinDrawLoss winDrawLoss = winDrawLossValueMap.getOrDefault(value, new WinDrawLoss());
        if (win) {
            winDrawLoss.addWin();
        }
        if (draw) {
            winDrawLoss.addDraw();
        }
        if (loss) {
            winDrawLoss.addLoss();
        }
        winDrawLossValueMap.put(value, winDrawLoss);
        homeWinLossRatioMap.put(lookback, winDrawLossValueMap);
    }
    public void addAwayWinLossRatio(int lookback, int value, boolean win, boolean draw, boolean loss) {
        Map<Integer,WinDrawLoss> winDrawLossValueMap = awayWinLossRatioMap.getOrDefault(lookback, new HashMap<>());
        WinDrawLoss winDrawLoss = winDrawLossValueMap.getOrDefault(value, new WinDrawLoss());
        if (win) {
            winDrawLoss.addWin();
        }
        if (draw) {
            winDrawLoss.addDraw();
        }
        if (loss) {
            winDrawLoss.addLoss();
        }
        winDrawLossValueMap.put(value,winDrawLoss);
        awayWinLossRatioMap.put(lookback, winDrawLossValueMap);
    }
    public void addHomeWinLossRatioHomeAndAwayMap(int lookback, int value, boolean win, boolean draw, boolean loss) {
        Map<Integer,WinDrawLoss> winDrawLossValueMap = homeWinLossRatioHomeAndAwayMap.getOrDefault(lookback, new HashMap<>());
        WinDrawLoss winDrawLoss = winDrawLossValueMap.getOrDefault(value, new WinDrawLoss());
        if (win) {
            winDrawLoss.addWin();
        }
        if (draw) {
            winDrawLoss.addDraw();
        }
        if (loss) {
            winDrawLoss.addLoss();
        }
        winDrawLossValueMap.put(value, winDrawLoss);
        homeWinLossRatioHomeAndAwayMap.put(lookback, winDrawLossValueMap);
    }
    public void addAwayWinLossRatioHomeAndAwayMap(int lookback, int value, boolean win, boolean draw, boolean loss) {
        Map<Integer, WinDrawLoss> winDrawLossValueMap = awayWinLossRatioHomeAndAwayMap.getOrDefault(lookback, new HashMap<>());
        WinDrawLoss winDrawLoss = winDrawLossValueMap.getOrDefault(value, new WinDrawLoss());
        if (win) {
            winDrawLoss.addWin();
        }
        if (draw) {
            winDrawLoss.addDraw();
        }
        if (loss) {
            winDrawLoss.addLoss();
        }
        winDrawLossValueMap.put(value,winDrawLoss);
        awayWinLossRatioHomeAndAwayMap.put(lookback, winDrawLossValueMap);
    }


    public void addHomeScoringTotal(int lookback, int value, boolean win, boolean draw, boolean loss) {

        Map<Integer, WinDrawLoss> winDrawLossValueMap = homeScoringTotal.getOrDefault(lookback, new HashMap<>());
        WinDrawLoss winDrawLoss = winDrawLossValueMap.getOrDefault(value, new WinDrawLoss());

        if (win) {
            winDrawLoss.addWin();
        }
        if (draw) {
            winDrawLoss.addDraw();
        }
        if (loss) {
            winDrawLoss.addLoss();
        }
        winDrawLossValueMap.put(value, winDrawLoss);
        homeScoringTotal.put(lookback, winDrawLossValueMap);
    }
    public void addAwayScoringTotal(int lookback, int value, boolean win, boolean draw, boolean loss) {
        Map<Integer,WinDrawLoss> winDrawLossValueMap = awayScoringTotal.getOrDefault(lookback, new HashMap<>());
        WinDrawLoss winDrawLoss = winDrawLossValueMap.getOrDefault(value, new WinDrawLoss());
        if (win) {
            winDrawLoss.addWin();
        }
        if (draw) {
            winDrawLoss.addDraw();
        }
        if (loss) {
            winDrawLoss.addLoss();
        }
        winDrawLossValueMap.put(value, winDrawLoss);
        awayScoringTotal.put(lookback, winDrawLossValueMap);
    }

    public void addScoringDiffLastGamesMap(int lookback, int value, boolean win, boolean draw, boolean loss) {
        Map<Integer,WinDrawLoss> winDrawLossValueMap = scoringDiffLastGamesMap.getOrDefault(lookback, new HashMap<>());
        WinDrawLoss winDrawLoss = winDrawLossValueMap.getOrDefault(value, new WinDrawLoss());
        if (win) {
            winDrawLoss.addWin();
        }
        if (draw) {
            winDrawLoss.addDraw();
        }
        if (loss) {
            winDrawLoss.addLoss();
        }
        winDrawLossValueMap.put(value, winDrawLoss);
        scoringDiffLastGamesMap.put(lookback, winDrawLossValueMap);
    }


    public GamePercentages getAwayScoringWinPercentage(int lookback, int awayScoringTotal) {
        Map<Integer, WinDrawLoss> mappedValues = this.awayScoringTotal.getOrDefault(lookback, new HashMap<>());
        WinDrawLoss values = mappedValues.getOrDefault(awayScoringTotal, null);
        if (values == null) {
            return new GamePercentages();
        }
        return new GamePercentages((float) values.getWins() / (float) values.getTotal(),
                (float) values.getDraws() / (float) values.getTotal(),
        (float) values.getLosses() / (float) values.getTotal());
    }

    public GamePercentages getHomeScoringWinPercentage(int lookback, int homeScoringTotal) {
        Map<Integer, WinDrawLoss> mappedValues = this.homeScoringTotal.getOrDefault(lookback, new HashMap<>());
        WinDrawLoss values = mappedValues.getOrDefault(homeScoringTotal, null);
        if (values == null) {
            return new GamePercentages();
        }
        return new GamePercentages((float) values.getWins() / (float) values.getTotal(),
                (float) values.getDraws() / (float) values.getTotal(),
                (float) values.getLosses() / (float) values.getTotal());
    }

    public GamePercentages getHomeWinRatioPercetage(int lookback, int homeWinLossRatio) {
        Map<Integer, WinDrawLoss> mappedValues = this.homeWinLossRatioMap.getOrDefault(lookback, new HashMap<>());
        WinDrawLoss values = mappedValues.getOrDefault(homeWinLossRatio, null);
        if (values == null) {
            return new GamePercentages();
        }
        return new GamePercentages((float) values.getWins() / (float) values.getTotal(),
                (float) values.getDraws() / (float) values.getTotal(),
                (float) values.getLosses() / (float) values.getTotal());
    }

    public GamePercentages getAwayWinRatioPercetage(int lookback, int awayWinLossRatio) {
        Map<Integer, WinDrawLoss> mappedValues = this.awayWinLossRatioMap.getOrDefault(lookback, new HashMap<>());
        WinDrawLoss values = mappedValues.getOrDefault(awayWinLossRatio, null);
        if (values == null) {
            return new GamePercentages();
        }
        return new GamePercentages((float) values.getWins() / (float) values.getTotal(),
                (float) values.getDraws() / (float) values.getTotal(),
                (float) values.getLosses() / (float) values.getTotal());
    }

    public GamePercentages getHomeWinLossRatioHomeAndAwayPercentage(int lookback, int homeWinLossRatioHomeAndAway) {
        Map<Integer, WinDrawLoss> mappedValues = this.homeWinLossRatioHomeAndAwayMap.getOrDefault(lookback, new HashMap<>());
        WinDrawLoss values = mappedValues.getOrDefault(homeWinLossRatioHomeAndAway, null);
        if (values == null) {
            return new GamePercentages();
        }
        return new GamePercentages((float) values.getWins() / (float) values.getTotal(),
                (float) values.getDraws() / (float) values.getTotal(),
                (float) values.getLosses() / (float) values.getTotal());
    }

    public GamePercentages getAwayWinLossRatioHomeAndAwayPercentage(int lookback, int awayWinLossRatioHomeAndAway) {
        Map<Integer, WinDrawLoss> mappedValues = this.awayWinLossRatioHomeAndAwayMap.getOrDefault(lookback, new HashMap<>());
        WinDrawLoss values = mappedValues.getOrDefault(awayWinLossRatioHomeAndAway, null);
        if (values == null) {
            return new GamePercentages();
        }
        return new GamePercentages((float) values.getWins() / (float) values.getTotal(),
                (float) values.getDraws() / (float) values.getTotal(),
                (float) values.getLosses() / (float) values.getTotal());
    }

    public GamePercentages getScoringDiffLastGamesPercentage(int lookback, int scoringDiffLastGames) {
        Map<Integer, WinDrawLoss> mappedValues = this.scoringDiffLastGamesMap.getOrDefault(lookback, new HashMap<>());
        WinDrawLoss values = mappedValues.getOrDefault(scoringDiffLastGames, null);
        if (values == null) {
            return new GamePercentages();
        }
        return new GamePercentages((float) values.getWins() / (float) values.getTotal(),
                (float) values.getDraws() / (float) values.getTotal(),
                (float) values.getLosses() / (float) values.getTotal());
    }


    private class WinDrawLoss {
        int wins = 0;
        int draws = 0;
        int losses = 0;

        int total = 0;

        public int getWins() {
            return wins;
        }

        public void addWin() {
            this.wins++; total++;
        }

        public int getDraws() {
            return draws;
        }

        public void addDraw() {
            this.draws++; total++;
        }

        public int getLosses() {
            return losses;
        }

        public void addLoss() {
            this.losses++; total++;
        }

        public int getTotal() {
            return total;
        }
    }
}
