package io.delphiplatform.api.v3.rdb.service;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;

import java.util.List;
import java.util.Locale;
import java.util.Set;

import io.delphiplatform.api.v3.model.tiktok.TikTokChartType;
import io.delphiplatform.api.v3.model.tiktok.top.TikTokTopChart;
import io.delphiplatform.api.v3.model.tiktok.top.TikTokTopCharts;
import io.delphiplatform.api.v3.rdb.entity.CommonJpaPropertyNames;
import io.delphiplatform.api.v3.rdb.entity.tiktok.TikTokTopTrackChartEntity;
import io.delphiplatform.api.v3.rdb.repository.TikTokTopTrackChartRepository;
import io.delphiplatform.api.v3.rdb.service.specification.SpecificationProvider;
import io.delphiplatform.api.v3.rdb.service.tiktok.TikTokTopTrackChartsService;
import io.delphiplatform.api.v3.view.util.Params;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;

public class TikTokTopTrackChartsServiceTest {

    private static final String ITALY = "it";
    private static final String FRANCE = "fr";

    @Spy
    @InjectMocks
    private TikTokTopTrackChartsService service;

    @Mock
    private TikTokTopTrackChartRepository repository;

    @Mock
    private SpecificationProvider<TikTokTopTrackChartEntity> specificationProvider;

    private Specification<TikTokTopTrackChartEntity> specification;


    @BeforeEach
    public void setUp() {
        initMocks(this);
    }

    @Test
    void getTikTokTopCharts() {
        TikTokTopTrackChartEntity tikTokTopTrackChartEntity = new TikTokTopTrackChartEntity();
        tikTokTopTrackChartEntity.setCountryCode(ITALY);
        tikTokTopTrackChartEntity.setSize(7);
        tikTokTopTrackChartEntity.setType(TikTokChartType.ISRC_PERIOD_CREATIONS);
        tikTokTopTrackChartEntity.setTotalPositions(100);

        TikTokTopTrackChartEntity tikTokTopTrackChartEntity2 = new TikTokTopTrackChartEntity();
        tikTokTopTrackChartEntity2.setCountryCode(FRANCE);
        tikTokTopTrackChartEntity2.setSize(17);
        tikTokTopTrackChartEntity2.setPeriodDays(7);
        tikTokTopTrackChartEntity2.setType(TikTokChartType.ISRC_PERIOD_CREATIONS);
        tikTokTopTrackChartEntity2.setTotalPositions(200);

        when(repository.findAll(eq(specification), any(Pageable.class)))
            .thenReturn(new PageImpl<>(List.of(tikTokTopTrackChartEntity, tikTokTopTrackChartEntity2)));

        Params params = getRequestParams(Set.of(7), Set.of(TikTokChartType.ISRC_PERIOD_CREATIONS),
            Set.of(FRANCE, ITALY));

        when(specificationProvider.multiValueSpec(CommonJpaPropertyNames.PERIOD_DAYS,
            params.getPeriodDays())).thenReturn(specification);

        when(specificationProvider.multiValueSpec(CommonJpaPropertyNames.COUNTRY_CODE,
            params.getCountryCode())).thenReturn(specification);

        TikTokTopCharts report = service.getTikTokTopCharts(params);
        Assertions.assertEquals(2, report.getCount());
        TikTokTopChart chart1 = TikTokTopChart.builder()
            .type(TikTokChartType.ISRC_PERIOD_CREATIONS)
            .countryCode(FRANCE)
            .periodDays(7)
            .size(17)
            .totalPositions(200)
            .build();

        TikTokTopChart chart2 = TikTokTopChart.builder()
            .type(TikTokChartType.ISRC_PERIOD_CREATIONS)
            .countryCode(ITALY)
            .size(7)
            .totalPositions(100)
            .build();

        org.assertj.core.api.Assertions.assertThat(List.of(chart1, chart2))
            .containsExactlyInAnyOrderElementsOf(report.getItems());

        verify(specificationProvider)
            .multiValueSpec(eq(CommonJpaPropertyNames.PERIOD_DAYS), eq(params.getPeriodDays()));
        verify(specificationProvider).multiValueSpec(eq(CommonJpaPropertyNames.TYPE), eq(params.getTikTokChartTypes()));
        verify(specificationProvider)
            .multiValueSpec(eq(CommonJpaPropertyNames.COUNTRY_CODE), eq(params.getCountryCode()));
    }

    @Test
    void getTikTokTopChartName() {
        TikTokTopChart chart1 = TikTokTopChart.builder()
            .countryCode(Locale.US.getCountry())
            .periodDays(1)
            .type(TikTokChartType.ISRC_PERIOD_CREATIONS)
            .build();
        Assertions.assertEquals("Top TikTok Creations - Last Day US", chart1.getName());
        TikTokTopChart chart2 = TikTokTopChart.builder()
            .countryCode(Locale.US.getCountry())
            .periodDays(1)
            .type(TikTokChartType.ISRC_PERIOD_CREATIONS_CHANGE)
            .build();
        Assertions.assertEquals("Top TikTok Gainers in Creations - Last Day US", chart2.getName());
        TikTokTopChart chart3 = TikTokTopChart.builder()
            .countryCode(Locale.US.getCountry())
            .periodDays(1)
            .type(TikTokChartType.PRODUCT_FAMILY_PERIOD_CREATIONS)
            .build();
        Assertions.assertEquals("Top TikTok Product Family Creations - Last Day US", chart3.getName());
        TikTokTopChart chart4 = TikTokTopChart.builder()
            .countryCode(Locale.US.getCountry())
            .periodDays(1)
            .type(TikTokChartType.PRODUCT_FAMILY_PERIOD_CREATIONS_CHANGE)
            .build();
        Assertions.assertEquals("Top TikTok Product Family Gainers in Creations - Last Day US", chart4.getName());
        TikTokTopChart chart5 = TikTokTopChart.builder()
            .countryCode(Locale.US.getCountry())
            .periodDays(2)
            .type(TikTokChartType.ISRC_PERIOD_CREATIONS)
            .build();
        Assertions.assertEquals("Top TikTok Creations - Last 7 Days US", chart5.getName());
        TikTokTopChart chart6 = TikTokTopChart.builder()
            .countryCode(Locale.US.getCountry())
            .periodDays(2)
            .type(TikTokChartType.ISRC_PERIOD_CREATIONS_CHANGE)
            .build();
        Assertions.assertEquals("Top TikTok Gainers in Creations - Last 7 Days US", chart6.getName());
        TikTokTopChart chart7 = TikTokTopChart.builder()
            .countryCode(Locale.US.getCountry())
            .periodDays(2)
            .type(TikTokChartType.PRODUCT_FAMILY_PERIOD_CREATIONS)
            .build();
        Assertions.assertEquals("Top TikTok Product Family Creations - Last 7 Days US", chart7.getName());
        TikTokTopChart chart8 = TikTokTopChart.builder()
            .countryCode(Locale.US.getCountry())
            .periodDays(2)
            .type(TikTokChartType.PRODUCT_FAMILY_PERIOD_CREATIONS_CHANGE)
            .build();
        Assertions.assertEquals("Top TikTok Product Family Gainers in Creations - Last 7 Days US", chart8.getName());
    }


    private Params getRequestParams(Set<Integer> periodDays, Set<TikTokChartType> types, Set<String> countries) {
        return Params.builder()
            .periodDays(periodDays)
            .tikTokChartTypes(types)
            .countryCode(countries)
            .build();
    }

}
