package cz.muni.fi.pa165.soccermanager.service;

import cz.muni.fi.pa165.soccermanager.dto.LeagueDto;
import cz.muni.fi.pa165.soccermanager.dto.request.CreateLeagueRequest;
import cz.muni.fi.pa165.soccermanager.entity.League;
import cz.muni.fi.pa165.soccermanager.entity.Team;
import cz.muni.fi.pa165.soccermanager.mapper.LeagueMapper;
import cz.muni.fi.pa165.soccermanager.service.impl.LeagueServiceImpl;
import cz.muni.fi.pa165.soccermanager.repository.LeagueRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class LeagueServiceTest {

    @Mock
    private LeagueRepository leagueRepository;

    @Mock
    private LeagueMapper leagueMapper;

    @InjectMocks
    private LeagueServiceImpl leagueService;


    @Test
    public void updateTest() {
        League league = new League();
        league.setId(1L);
        league.setName("1");
        league.setStartDate(LocalDate.of(2022, 1, 13));
        league.setEndDate(LocalDate.of(2022, 2, 13));

        LeagueDto dto = new LeagueDto();
        dto.setName("2");
        dto.setStartDate(LocalDate.of(2022, 1, 13));
        dto.setEndDate(LocalDate.of(2022, 2, 13));

        when(leagueRepository.findById(league.getId())).thenReturn(Optional.of(league));

        leagueService.update(1L,dto);
        verify(leagueMapper, times(1)).mapOnUpdate(league,dto);
    }

    @ParameterizedTest
    @ValueSource(longs = {1L, 2L, 3L})
    public void findLeagueByIdTest(Long id) {
        final var l = new League();
        final var dto = new LeagueDto();

        when(leagueRepository.findById(any(Long.class))).thenReturn(Optional.of(l));
        when(leagueMapper.map(any(League.class))).thenReturn(dto);

        assertTrue(leagueService.findLeagueById(id).isPresent());

        final var l1 = ArgumentCaptor.forClass(League.class);

        verify(leagueRepository, times(1)).findById(id);
        verify(leagueMapper, times(1)).map(l1.capture());

        assertEquals(l, l1.getValue());
    }

    @Test
    public void resetLeagueTest() {
        League league = new League();
        league.setId(1L);
        league.setName("name");
        league.setStartDate(LocalDate.of(2022, 1, 13));
        league.setEndDate(LocalDate.of(2022, 2, 13));

        Team team = new Team();
        team.setName("name");
        team.setPoints(1);
        team.setGround("ground");
        team.setMatches(new ArrayList<>());
        league.setTeams(List.of(team));

        when(leagueRepository.findById(any(Long.class))).thenReturn(Optional.of(league));
        leagueService.resetLeague(league.getId());

        verify(leagueRepository, times(1)).saveAndFlush(league);
    }

    @Test
    public void createLeagueTest() {
        final var league = new CreateLeagueRequest();
        when(leagueRepository.saveAndFlush(any(League.class))).thenReturn(new League());
        when(leagueMapper.map(any(CreateLeagueRequest.class))).thenReturn(new League());
        leagueService.createLeague(league);
        verify(leagueMapper).map(league);
        verify(leagueRepository, times(1)).saveAndFlush(any(League.class));
    }

    @Test
    public void getAllLeaguesTest(){
        when(leagueRepository.findAll(any(PageRequest.class))).thenReturn(Page.empty());
        assertEquals(leagueService.getAllLeagues(10,10,"id"), Page.empty());
    }
}
