package tests;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import com.google.common.collect.Lists;

import data.GuiMysql;
import objects.League;
import objects.SoccerMatch;
import objects.TeamResults;

public class HomeDrawAwayTest extends TestClass {

    private ArrayList<League> prioLeagues;
    private float activeOdds1;
    private float activeOddsX;
    private float activeOdds2;

    public ArrayList<SoccerMatch> getMatches() {
        final ArrayList<SoccerMatch> matches = new ArrayList<>();
        prioLeagues = getPrioLeagues();

        final ArrayList<String> leagueIds = Lists.newArrayList();
        prioLeagues.forEach(p -> leagueIds.add(String.valueOf(p.getLeagueId())));

        final String sql = "SELECT res.*, " + "hTeam.name as homeTeamName, aTeam.name as awayTeamName "
                + "FROM SoccerResults as res "
                + "Join Team as hTeam ON res.homeTeam = hTeam.id " + "Join Team as aTeam ON res.awayTeam = aTeam.id "
                + "WHERE "
                + "DATE(gameDate) > '2021-07-01' AND " + "homeScore >= 0 AND " + "awayScore >= 0 AND "
                + "res.leagueId IN ("
                + String.join(",", leagueIds) + ") " + "ORDER BY gameDate ASC";

        PreparedStatement stmt;
        try {
            stmt = getConnection().prepareStatement(sql);
            matches.addAll(super.getMatches(stmt));
        } catch (final SQLException e) {
            e.printStackTrace();
        }

        return matches;
    }

    @Override
    public void runTest() {
        float betAmount;
        float bank = startingBank;
        final float betLevel = bettingLevel / 100.0f;

        float homeBank = startingBank;
        float drawBank = startingBank;
        float awayBank = startingBank;

        final ArrayList<SoccerMatch> matches = getMatches();

        for (int i = 0; i < matches.size(); i++) {
            final SoccerMatch soccerMatch = matches.get(i);

            final List<SoccerMatch> matchesThisDate = matches.stream().filter(
                    p -> p.getGameDate().format(DateTimeFormatter.ISO_DATE)
                            .equals(soccerMatch.getGameDate().format(DateTimeFormatter.ISO_DATE)))
                    .collect(Collectors.toList());

            final int matchesThisDateCount = matchesThisDate.size();
            betAmount = bank * betLevel;
            int gamesBettedOn = 0;
            int winsThisDay = 0;
            final float startBank = bank;
            for (final SoccerMatch sm : matchesThisDate) {
                final int leagueId = sm.getHomeTeam().getTeamLeagueId();
                final League activeLeague = prioLeagues.stream().filter(p -> p.getLeagueId() == leagueId).findFirst()
                        .get();

                final String betOnThisMatch = checkWhatBet(sm, activeLeague);
                if (!"NoBet".equals(betOnThisMatch)) {
                    if (betOnThisMatch.contains("1")) { // Spela p� hemma lag
                        gamesBettedOn++;
                        bank = bank - betAmount;
                        final float homeBetAmount = (homeBank * betLevel);
                        homeBank -= homeBetAmount;

                        if (sm.getHomeScore() > sm.getAwayScore()) {
                            bank += betAmount * sm.getOdds1();
                            homeBank += homeBetAmount * sm.getOdds1();
                            winsThisDay++;
                        }
                    }
                    if (betOnThisMatch.contains("2")) { // Spela p� borta lag
                        gamesBettedOn++;
                        bank = bank - betAmount;

                        final float awayBetAmount = (awayBank * betLevel);
                        awayBank -= awayBetAmount;
                        if (sm.getAwayScore() > sm.getHomeScore()) {
                            bank += betAmount * sm.getOdds2();
                            awayBank += awayBetAmount * sm.getOdds2();
                            winsThisDay++;
                        }
                    }
                    if (betOnThisMatch.contains("X")) { // Spela p� Lika
                        gamesBettedOn++;
                        bank = bank - betAmount;

                        final float drawBetAmount = (drawBank * betLevel);
                        drawBank -= drawBetAmount;
                        if (sm.getHomeScore() == sm.getAwayScore()) {
                            bank += betAmount * sm.getOddsX();
                            drawBank += drawBetAmount * sm.getOddsX();
                            winsThisDay++;
                        }
                    }
                }
                System.out.println("Match between " + sm.getHomeTeam().getTeamName() + " - "
                        + sm.getAwayTeam().getTeamName() + " result "
                        + sm.getHomeScore() + " - " + sm.getAwayScore() + " Betted on " + betOnThisMatch + " at odds "
                        + sm.getOdds1() + ", "
                        + sm.getOddsX() + ", " + sm.getOdds2() + " Bet Amount: " + betAmount + " calc odds: "
                        + activeOdds1 + ", " + activeOddsX
                        + ", " + activeOdds2);
            }

            System.out.println(matchesThisDate.get(0).getGameDate() + " result " + (bank - startBank)
                    + " current bank: " + bank + " bet on "
                    + gamesBettedOn + "/" + matchesThisDateCount + " wins " + winsThisDay);
            i += matchesThisDate.size();

        }

        System.out.println(
                "Final bank " + bank + " homeBank " + homeBank + " drawBank " + drawBank + " awayBank " + awayBank);
    }

    private String checkWhatBet(SoccerMatch sm, League activeLeague) {
        String result = "NoBet";
        final float betMarginHomeDecimal = 1 + (activeLeague.getBetMarginHome() / 100f);
        final float betMarginDrawDecimal = 1 + (activeLeague.getBetMarginDraw() / 100f);
        final float betMarginAwayDecimal = 1 + (activeLeague.getBetMarginAway() / 100f);

        final int lookbackHome = activeLeague.getLookbackHome();
        final int lookbackDraw = activeLeague.getLookbackDraw();
        final int lookbackAway = activeLeague.getLookbackAway();

        if (lookbackHome > 0) {
            final TeamResults homeTeamResults = GuiMysql.getInstance().getTeamResultsTest(sm.getHomeTeam().getTeamId(),
                    activeLeague.getLookbackHome(), true, sm.getGameDate().format(DateTimeFormatter.ISO_DATE));
            final TeamResults awayTeamResults = GuiMysql.getInstance().getTeamResultsTest(sm.getAwayTeam().getTeamId(),
                    activeLeague.getLookbackHome(), false, sm.getGameDate().format(DateTimeFormatter.ISO_DATE));
            final float homeWinPercent = (homeTeamResults.getWins() + awayTeamResults.getLosses())
                    / Float.valueOf(homeTeamResults.getCount() + awayTeamResults.getCount()) * 100;
            final float homeOdds = 100 / homeWinPercent;

            activeOdds1 = homeOdds * betMarginHomeDecimal;
            if (activeLeague.getBetMarginHome() > 0 && homeOdds * betMarginHomeDecimal <= sm.getOdds1()) {
                if (result.equals("NoBet")) {
                    result = "1";
                } else {
                    result += "1";
                }
            }

        }

        if (lookbackDraw > 0) {
            final TeamResults homeTeamResults = GuiMysql.getInstance().getTeamResultsTest(sm.getHomeTeam().getTeamId(),
                    activeLeague.getLookbackDraw(), true, sm.getGameDate().format(DateTimeFormatter.ISO_DATE));
            final TeamResults awayTeamResults = GuiMysql.getInstance().getTeamResultsTest(sm.getAwayTeam().getTeamId(),
                    activeLeague.getLookbackDraw(), false, sm.getGameDate().format(DateTimeFormatter.ISO_DATE));
            final float drawWinPercent = (homeTeamResults.getDraws() + awayTeamResults.getDraws())
                    / Float.valueOf(homeTeamResults.getCount() + awayTeamResults.getCount()) * 100;
            final float drawOdds = 100 / drawWinPercent;

            activeOddsX = drawOdds * betMarginDrawDecimal;
            if (activeLeague.getBetMarginDraw() > 0 && drawOdds * betMarginDrawDecimal <= sm.getOddsX()) {
                if (result.equals("NoBet")) {
                    result = "X";
                } else {
                    result += "X";
                }
            }

        }

        if (lookbackAway > 0) {
            final TeamResults homeTeamResults = GuiMysql.getInstance().getTeamResultsTest(sm.getHomeTeam().getTeamId(),
                    activeLeague.getLookbackAway(), true, sm.getGameDate().format(DateTimeFormatter.ISO_DATE));
            final TeamResults awayTeamResults = GuiMysql.getInstance().getTeamResultsTest(sm.getAwayTeam().getTeamId(),
                    activeLeague.getLookbackAway(), false, sm.getGameDate().format(DateTimeFormatter.ISO_DATE));
            final float awayWinPercent = (awayTeamResults.getWins() + homeTeamResults.getLosses())
                    / Float.valueOf(awayTeamResults.getCount() + homeTeamResults.getCount()) * 100;
            final float awayOdds = 100 / awayWinPercent;

            activeOdds2 = awayOdds * betMarginAwayDecimal;
            if (activeLeague.getBetMarginHome() > 0 && awayOdds * betMarginAwayDecimal <= sm.getOdds2()) {
                if (result.equals("NoBet")) {
                    result = "2";
                } else {
                    result += "2";
                }
            }

        }
        return result;
    }

    private ArrayList<League> getPrioLeagues() {
        final String sql = "SELECT * FROM League WHERE prio = 1";
        final ArrayList<League> result = Lists.newArrayList();
        try {
            final PreparedStatement stat = getConnection().prepareStatement(sql);
            final ResultSet rs = stat.executeQuery();

            while (rs.next()) {
                result.add(new League(rs.getInt("id"), rs.getString("name"), rs.getInt("scoringDiffLastGame"),
                        rs.getInt("scoringTotal"),
                        rs.getInt("winLossRatioHomeAndAway"), rs.getInt("winLossRatio"), rs.getInt("drawDiffHomeAway"),
                        rs.getInt("drawDiffTotalGoals"), rs.getInt("drawWinningForm"),
                        rs.getInt("drawWinngingFormHomeAway")));
            }
        } catch (final SQLException e) {
            e.printStackTrace();
        }

        return result;
    }

}
