package tests;

import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import data.TestDatabase;
import objects.SoccerMatch;
import tests.objects.LeagueDTO;
import tests.objects.Standing;

public class LeagueTablePositionTest extends TestClass {

    @Override
    public void runTest() {
        List<LeagueDTO> prioLeagues = TestDatabase.getInstance().getPrioLeagues();

        for (LeagueDTO league : prioLeagues) {
            if (league.getName().equals("championship")) {
                runLeagueTest(league);
            }
        }

    }

    private void runLeagueTest(LeagueDTO league) {
        getMatches(league);
    }

    private void getMatches(LeagueDTO league) {

        List<SoccerMatch> matches = TestDatabase.getInstance().getMatches(league);
        List<String> seasons = matches.stream().map(SoccerMatch::getSeason).distinct().sorted().toList();

        for (String season : seasons.subList(1, seasons.size())) {
            List<SoccerMatch> seasonMatches = matches.stream().filter(p -> p.getSeason().equals(season)).toList();
            Map<String, Integer> intervals = getIntervals(seasonMatches);
            int skipFirstXMatches = 10;
            int currentMatch = 0;

            int testValue = 0;

            seasonMatches = seasonMatches.stream().sorted((m1, m2) -> m1.getGameDate().compareTo(m2.getGameDate()))
                    .toList();

            for (SoccerMatch match : seasonMatches) {
                List<Standing> standings = getStandings(
                        seasonMatches.stream().filter(p -> p.getGameDate().isBefore(match.getGameDate())).toList());

                standings = standings.stream().sorted((s1, s2) -> Integer.compare(s2.getPoints(), s1.getPoints()))
                        .toList();

                Optional<Standing> homeTeamStanding = standings.stream()
                        .filter(p -> p.getTeamName().equals(match.getHomeTeam().getTeamName()))
                        .findFirst();
                Optional<Standing> awayTeamStanding = standings.stream()
                        .filter(p -> p.getTeamName().equals(match.getAwayTeam().getTeamName()))
                        .findFirst();
                if (homeTeamStanding.isPresent() && awayTeamStanding.isPresent()
                        && homeTeamStanding.get().getGamesPlayed() >= skipFirstXMatches) {
                    Standing hts = homeTeamStanding.get();
                    Standing ats = awayTeamStanding.get();

                    int homeTeamPosition = standings.indexOf(hts);
                    int awayTeamPosition = standings.indexOf(ats);

//					System.out.println(String.format("%s Hometeam %s position %s Awayteam %s position %s Diff %s", season, hts.getTeamName(),
//							homeTeamPosition, ats.getTeamName(), awayTeamPosition, homeTeamPosition - awayTeamPosition));
//					standings.forEach(s -> System.out.println(String.format("%s \t\t wins %s \t draws %s \t losses %s \t points %s \t gamesPlayed %s",
//							s.getTeamName(), s.getWins(), s.getDraws(), s.getLosses(), s.getPoints(), s.getGamesPlayed())));

                    List<SoccerMatch> matchesBefore = matches.stream()
                            .filter(p -> p.getGameDate().isBefore(match.getGameDate())).toList();
                    matchesBefore = matchesBefore.stream()
                            .sorted((m1, m2) -> m1.getGameDate().compareTo(m2.getGameDate())).toList();
                    float avgGoals = getAvgGoalsWithSameDiff(matchesBefore,
                            Math.abs(homeTeamPosition - awayTeamPosition));
                    List<Float> leagueAvarages = TestDatabase.getInstance().getLeagueAvarages(
                            match.getHomeTeam().getTeamLeagueId(),
                            match.getHomeTeam().getCountryId(),
                            match.getGameDate().format(DateTimeFormatter.BASIC_ISO_DATE));
                    if (Math.abs(avgGoals - (leagueAvarages.get(0) + leagueAvarages.get(1))) > 0.5) {
                        System.out.println(String.format(
                                "%s homeTeam: %s (%s) - awayTeam: %s (%s) Avg goals with diff %s is %s and leagueAvg is %s makes diff %s intervals is low %s mid %s high %s",
                                match.getGameDate(), match.getHomeTeam().getTeamName(), homeTeamPosition,
                                match.getAwayTeam().getTeamName(),
                                awayTeamPosition, Math.abs(homeTeamPosition - awayTeamPosition), avgGoals,
                                leagueAvarages.get(0) + leagueAvarages.get(1),
                                avgGoals - (leagueAvarages.get(0) + leagueAvarages.get(1)),
                                intervals.get("Low"), intervals.get("Low") + intervals.get("Mid"),
                                intervals.get("Low") + intervals.get("Mid") + intervals.get("High")));
                    }
                }

            }
        }
    }

    private float getAvgGoalsWithSameDiff(List<SoccerMatch> matchesBefore, int placementDiff) {
        List<Standing> tempStanding = new ArrayList<>();
        float result = 0.0f;
        int matchedMatches = 0;
        for (SoccerMatch match : matchesBefore) {
            Optional<Standing> homeTeamStanding = tempStanding.stream()
                    .filter(ts -> ts.getTeamName().equals(match.getHomeTeam().getTeamName()))
                    .findFirst();
            Optional<Standing> awayTeamStanding = tempStanding.stream()
                    .filter(ts -> ts.getTeamName().equals(match.getAwayTeam().getTeamName()))
                    .findFirst();

            if (homeTeamStanding.isPresent() && awayTeamStanding.isPresent()) {
                int homeTeamPosition = tempStanding.indexOf(homeTeamStanding.get());
                int awayTeamPosition = tempStanding.indexOf(awayTeamStanding.get());

                int diff = Math.abs(homeTeamPosition - awayTeamPosition);

                if (diff == placementDiff) {
                    matchedMatches++;
                    result += match.getHomeScore() + match.getAwayScore();
                }
            }
            updateStanding(tempStanding, match,
                    tempStanding.stream().filter(p -> p.getTeamName().equals(match.getHomeTeam().getTeamName()))
                            .findFirst(),
                    tempStanding.stream().filter(p -> p.getTeamName().equals(match.getAwayTeam().getTeamName()))
                            .findFirst());

            tempStanding.sort((s1, s2) -> Integer.compare(s2.getPoints(), s1.getPoints()));
        }

        return matchedMatches > 0 ? result / matchedMatches : 0f;
    }

    private Map<String, Integer> getIntervals(List<SoccerMatch> seasonMatches) {
        Map<String, Integer> result = new HashMap<>();

        List<String> teams = seasonMatches.stream().map(m -> m.getHomeTeam().getTeamName()).distinct().toList();
        result.put("Low", (int) Math.floor(teams.size() / 3.0));
        result.put("Mid", (int) Math.ceil(teams.size() / 3.0));
        result.put("High", (int) Math.floor(teams.size() / 3.0));

        return result;
    }

}
