package hdm.mi.sthbackend.serviceTests;

import hdm.mi.sthbackend.exeptions.TournamentIdNotFoundException;
import hdm.mi.sthbackend.model.BracketRound;
import hdm.mi.sthbackend.model.Match;
import hdm.mi.sthbackend.model.Tournament;
import hdm.mi.sthbackend.repository.ITournamentRepository;
import hdm.mi.sthbackend.service.TournamentService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.ArrayList;
import java.util.Optional;
import java.util.UUID;

import static hdm.mi.sthbackend.dummyObjects.dummyTournaments.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
public class FillBracketRandomTest {
    private final Logger log = LogManager.getLogger("FillBracketTest");

    @Mock
    ITournamentRepository tournamentRepository;
    @InjectMocks
    TournamentService tournamentService;


    private Tournament createDummyBracketAndMatches(int rounds, Tournament tournament){
        tournament.setBracket(new ArrayList<>());
        for (int i = 0; i < rounds; i++) {
            tournament.getBracket().add(new BracketRound(i));
            for (int j = 0; j < (Math.pow(2,rounds) / Math.pow(2, i + 1)); j++) {
                UUID matchId = UUID.randomUUID();
                tournament.getBracket().get(i).getMatches().put(matchId, new Match(matchId));
            }
        }
        return tournament;
    }

    private int calculateTeamSum(Tournament tournament){
        return tournament.getBracket()
                .stream()
                .flatMap(bracketRound -> bracketRound.getMatches().values().stream())
                .map(match -> match.getTeamScores().size())
                .reduce(0, Integer::sum);
    }

    @Test
    public void fill2TeamBracketRandomTest() throws TournamentIdNotFoundException {
        Tournament t1withMatches = createDummyBracketAndMatches(1, t1);

        when(tournamentRepository.findById(dummyTournamentId)).thenReturn(Optional.of(t1withMatches));
        Tournament t1Filled = tournamentService.fillBracketRandom(dummyTournamentId);

        int teamSum = calculateTeamSum(t1Filled);

        assertEquals(2,teamSum);
    }

    @Test
    public void fill4TeamBracketRandomTest() throws TournamentIdNotFoundException {
        Tournament t2withMatches = createDummyBracketAndMatches(2, t2);

        when(tournamentRepository.findById(dummyTournamentId)).thenReturn(Optional.of(t2withMatches));
        Tournament t2Filled = tournamentService.fillBracketRandom(dummyTournamentId);

        int teamSum = calculateTeamSum(t2Filled);

        assertEquals(4,teamSum);
    }

    @Test
    public void fill8TeamBracketRandomTest() throws TournamentIdNotFoundException {
        Tournament t3withMatches = createDummyBracketAndMatches(3, t3);

        when(tournamentRepository.findById(dummyTournamentId)).thenReturn(Optional.of(t3withMatches));
        Tournament t3Filled = tournamentService.fillBracketRandom(dummyTournamentId);

        int teamSum = calculateTeamSum(t3Filled);

        assertEquals(8,teamSum);

    }

    @Test
    public void fill16TeamBracketRandomTest() throws TournamentIdNotFoundException {
        Tournament t4withMatches = createDummyBracketAndMatches(4, t4);

        when(tournamentRepository.findById(dummyTournamentId)).thenReturn(Optional.of(t4withMatches));
        Tournament t4Filled = tournamentService.fillBracketRandom(dummyTournamentId);

        int teamSum = calculateTeamSum(t4Filled);

        assertEquals(16,teamSum);
    }
}