package io.delphiplatform.api.integration;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

import io.delphiplatform.api.integration.annotation.BigTable;
import io.delphiplatform.api.integration.model.StreamModelModel;
import io.delphiplatform.api.integration.model.StreamsModelModel;
import io.delphiplatform.api.integration.util.MockCurrentDateService;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class StreamsIT extends BaseIT {

    /**
     * <!-- @formatter:off -->
     * Check main flow of endpoint, based only on isrc param (without other identifiers)
     * Test dsp/country filters, also group_by=dsp is implicitly tested here
     *
     * CASE1: return data from all dsps and all countries
     * CASE2: return data filtered by single dsp and single country
     * <!-- @formatter:on -->
     */
    @Test
    @BigTable(table = "spotify", json = "/scripts/StreamsIT/BT_spotify_getStreams_mainFlow.json")
    @BigTable(table = "apple_music", json = "/scripts/StreamsIT/BT_apple_music_getStreams_mainFlow.json")
    @BigTable(table = "amazon_music", json = "/scripts/StreamsIT/BT_amazon_music_getStreams_mainFlow.json")
    public void getStreams_mainFlow() {
        MockCurrentDateService.setMockDateTime(LocalDateTime.parse("2023-01-31T00:00:00"));

        String isrc = "USRC11301214";

        String dsp1 = "spotify";
        String dsp2 = "apple";
        String dsp3 = "amazon";

        String countryCode1 = "us";
        String countryCode2 = "ca";

        long streamsDsp1 = 10L;
        long streamsDsp2 = 20L;
        long streamsDsp3_us = 30L;
        long streamsDsp3_ca = 40L;

        //CASE1

        ResponseEntity<StreamsModelModel> response1 = apiClient.sendAPIRequest(
            "/v3/streams?"
                + "start_date=" + "2022-12-01"
                + "&end_date=" + "2022-12-31"
                + "&isrc=" + isrc
                + "&group_by=sub_dsp", //group by dsp for results clarity
            StreamsModelModel.class
        );

        assertEquals(HttpStatus.OK, response1.getStatusCode());

        Assertions.assertEquals(HttpStatus.OK, response1.getStatusCode());
        Assertions.assertEquals(4, response1.getBody().getCount());

        List<StreamModelModel> items1 = response1.getBody().getItems();

        StreamModelModel item1_1 = items1.stream()
            .filter(m -> isrc.equals(m.getIsrc()) && dsp1.equals(m.getDsp()))
            .findFirst().orElse(null);

        Assertions.assertNotNull(item1_1);
        Assertions.assertEquals(streamsDsp1, item1_1.getStreams());

        StreamModelModel item1_2 = items1.stream()
            .filter(m -> isrc.equals(m.getIsrc()) && dsp2.equals(m.getDsp()))
            .findFirst().orElse(null);

        Assertions.assertNotNull(item1_2);
        Assertions.assertEquals(streamsDsp2, item1_2.getStreams());

        StreamModelModel item1_3_us = items1.stream()
            .filter(m -> isrc.equals(m.getIsrc()) && dsp3.equals(m.getDsp()) && countryCode1.equals(m.getCountryCode()))
            .findFirst().orElse(null);

        Assertions.assertNotNull(item1_3_us);
        Assertions.assertEquals(streamsDsp3_us, item1_3_us.getStreams());

        StreamModelModel item1_3_ca = items1.stream()
            .filter(m -> isrc.equals(m.getIsrc()) && dsp3.equals(m.getDsp()) && countryCode2.equals(m.getCountryCode()))
            .findFirst().orElse(null);

        Assertions.assertNotNull(item1_3_ca);
        Assertions.assertEquals(streamsDsp3_ca, item1_3_ca.getStreams());

        //CASE2

        ResponseEntity<StreamsModelModel> response2 = apiClient.sendAPIRequest(
            "/v3/streams?"
                + "start_date=" + "2022-12-01"
                + "&end_date=" + "2022-12-31"
                + "&isrc=" + isrc
                + "&dsp=" + dsp3
                + "&country_code=" + countryCode1
                + "&group_by=sub_dsp", //group by dsp for results clarity
            StreamsModelModel.class
        );

        assertEquals(HttpStatus.OK, response2.getStatusCode());

        Assertions.assertEquals(HttpStatus.OK, response2.getStatusCode());
        Assertions.assertEquals(1, response2.getBody().getCount());

        List<StreamModelModel> items2 = response2.getBody().getItems();

        StreamModelModel item2 = items2.stream()
            .filter(m -> isrc.equals(m.getIsrc()) && dsp3.equals(m.getDsp()))
            .findFirst().orElse(null);

        Assertions.assertNotNull(item2);
        Assertions.assertEquals(streamsDsp3_us, item2.getStreams());
    }

    /**
     * <!-- @formatter:off -->
     * Check main flow of endpoint, based only on isrc param (without other identifiers)
     * Test group_by parameter - group by date
     *
     * CASE1: return data without grouping by date - 2 dates merged into 1 record
     * CASE2: return data grouped by date - 2 separate records
     * <!-- @formatter:on -->
     */
    @Test
    @BigTable(table = "spotify", json = "/scripts/StreamsIT/BT_spotify_getStreams_mainFlow_groupBy_date.json")
    @BigTable(table = "apple_music", json = "/scripts/BT_empty.json")
    @BigTable(table = "amazon_music", json = "/scripts/BT_empty.json")
    public void getStreams_mainFlow_groupBy_date() {
        MockCurrentDateService.setMockDateTime(LocalDateTime.parse("2023-01-31T00:00:00"));

        String isrc = "USRC11301214";

        LocalDate date1 = LocalDate.parse("2022-12-29");
        LocalDate date2 = LocalDate.parse("2022-12-30");

        long streamsDate1 = 10L;
        long streamsDate2 = 20L;

        //CASE1

        ResponseEntity<StreamsModelModel> response1 = apiClient.sendAPIRequest(
            "/v3/streams?"
                + "start_date=" + "2022-12-01"
                + "&end_date=" + "2022-12-31"
                + "&isrc=" + isrc,
            StreamsModelModel.class
        );

        assertEquals(HttpStatus.OK, response1.getStatusCode());

        Assertions.assertEquals(HttpStatus.OK, response1.getStatusCode());
        Assertions.assertEquals(1, response1.getBody().getCount());

        List<StreamModelModel> items1 = response1.getBody().getItems();

        StreamModelModel item1_1 = items1.stream()
            .filter(m -> isrc.equals(m.getIsrc()))
            .findFirst().orElse(null);

        Assertions.assertNotNull(item1_1);
        Assertions.assertNull(item1_1.getDate());
        Assertions.assertEquals(streamsDate1 + streamsDate2, item1_1.getStreams());

        //CASE2

        ResponseEntity<StreamsModelModel> response2 = apiClient.sendAPIRequest(
            "/v3/streams?"
                + "start_date=" + "2022-12-01"
                + "&end_date=" + "2022-12-31"
                + "&isrc=" + isrc
                + "&group_by=date",
            StreamsModelModel.class
        );

        assertEquals(HttpStatus.OK, response2.getStatusCode());

        Assertions.assertEquals(HttpStatus.OK, response2.getStatusCode());
        Assertions.assertEquals(2, response2.getBody().getCount());

        List<StreamModelModel> items2 = response2.getBody().getItems();

        StreamModelModel item2_1 = items2.stream()
            .filter(m -> isrc.equals(m.getIsrc()) && date1.equals(m.getDate()))
            .findFirst().orElse(null);

        Assertions.assertNotNull(item2_1);
        Assertions.assertEquals(streamsDate1, item2_1.getStreams());

        StreamModelModel item2_2 = items2.stream()
            .filter(m -> isrc.equals(m.getIsrc()) && date2.equals(m.getDate()))
            .findFirst().orElse(null);

        Assertions.assertNotNull(item2_2);
        Assertions.assertEquals(streamsDate2, item2_2.getStreams());
    }

    /**
     * <!-- @formatter:off -->
     * Check main flow of endpoint, based only on isrc param (without other identifiers)
     * Test group_by parameter - group by country
     *
     * NOTE: currently grouping by country is performed by default, the only way to avoid it is to pass following param:
     * sum_up_country_codes=true
     *
     * CASE1: return data without grouping by country - 2 countries merged into 1 record
     * CASE2: return data grouped by country - 2 separate records
     * <!-- @formatter:on -->
     */
    @Test
    @BigTable(table = "spotify", json = "/scripts/StreamsIT/BT_spotify_getStreams_mainFlow_groupBy_country.json")
    @BigTable(table = "apple_music", json = "/scripts/BT_empty.json")
    @BigTable(table = "amazon_music", json = "/scripts/BT_empty.json")
    public void getStreams_mainFlow_groupBy_country() {
        MockCurrentDateService.setMockDateTime(LocalDateTime.parse("2023-01-31T00:00:00"));

        String isrc = "USRC11301214";

        String country1 = "us";
        String country2 = "ca";

        long streamsCountry1 = 10L;
        long streamsCountry2 = 20L;

        //CASE1

        ResponseEntity<StreamsModelModel> response1 = apiClient.sendAPIRequest(
            "/v3/streams?"
                + "start_date=" + "2022-12-01"
                + "&end_date=" + "2022-12-31"
                + "&isrc=" + isrc
                //currently grouping by country is performed by default, the only way to avoid it is to pass sum_up_country_codes=true
                + "&sum_up_country_codes=true",
            StreamsModelModel.class
        );

        assertEquals(HttpStatus.OK, response1.getStatusCode());

        Assertions.assertEquals(HttpStatus.OK, response1.getStatusCode());
        Assertions.assertEquals(1, response1.getBody().getCount());

        List<StreamModelModel> items1 = response1.getBody().getItems();

        StreamModelModel item1_1 = items1.stream()
            .filter(m -> isrc.equals(m.getIsrc()))
            .findFirst().orElse(null);

        Assertions.assertNotNull(item1_1);
        Assertions.assertNull(item1_1.getCountryCode());
        Assertions.assertEquals(streamsCountry1 + streamsCountry2, item1_1.getStreams());

        //CASE2

        ResponseEntity<StreamsModelModel> response2 = apiClient.sendAPIRequest(
            "/v3/streams?"
                + "start_date=" + "2022-12-01"
                + "&end_date=" + "2022-12-31"
                + "&isrc=" + isrc
                + "&group_by=country", //currently grouping by country is performed by default, so this is redundant
            StreamsModelModel.class
        );

        assertEquals(HttpStatus.OK, response2.getStatusCode());

        Assertions.assertEquals(HttpStatus.OK, response2.getStatusCode());
        Assertions.assertEquals(2, response2.getBody().getCount());

        List<StreamModelModel> items2 = response2.getBody().getItems();

        StreamModelModel item2_1 = items2.stream()
            .filter(m -> isrc.equals(m.getIsrc()) && country1.equals(m.getCountryCode()))
            .findFirst().orElse(null);

        Assertions.assertNotNull(item2_1);
        Assertions.assertEquals(streamsCountry1, item2_1.getStreams());

        StreamModelModel item2_2 = items2.stream()
            .filter(m -> isrc.equals(m.getIsrc()) && country2.equals(m.getCountryCode()))
            .findFirst().orElse(null);

        Assertions.assertNotNull(item2_2);
        Assertions.assertEquals(streamsCountry2, item2_2.getStreams());
    }
}
