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.util.List;

import io.delphiplatform.api.integration.annotation.SqlScript;
import io.delphiplatform.api.integration.model.LatestJunoSpotifyStreamsResultsModel;
import io.delphiplatform.api.v3.model.JunoSpotifyStreamsIncludes;
import io.delphiplatform.api.v3.model.spotify.LatestJunoSpotifyStreamsResult;

public class JunoSpotifyIT extends BaseIT {

    @Test
    @SqlScript(scripts = {"/scripts/JunoSpotifyIT/common_test_data_set_1.sql",
        "/scripts/JunoSpotifyIT/getLatestJunoSpotifyStreams_singleCountry.sql"})
    public void getLatestJunoSpotifyStreams_singleCountry() {
        //it actually means 'streams country code' here
        String countryCode1 = "us";
        String isrcCountryCode1 = "gb";

        String grasTrackId1 = "GRAS_A10328E00000000001";
        String grasTrackName1 = "testGrasTrackName1";

        String spotifyTrackId1 = "testSpotifyTrackId1";
        String spotifyTrackName1 = "tesrSpotifyTrackName1";
        String isrc1 = "USQX91901111";

        long streams17DaysTotal = 5;
        long streams814DaysTotal = 3;
        long streams17DaysLeanBack = 55;
        long streams814DaysLeanBack = 33;
        long streams17DaysLeanForward = 66;
        long streams814DaysLeanForward = 44;
        long streams17DaysMale = 3;
        long streams814DaysMale = 2;
        long streams17DaysFemale = 2;
        long streams814DaysFemale = 1;
        long streamsChange7To14Days = 2;

        double streamsChangePercent7To14Days = 66.6; //streams17DaysTotal (5) is 66.6% more than streams814DaysTotal (3)

        LocalDate latestEntryDate = LocalDate.parse("2022-05-16");
        LocalDate productSaleDate = LocalDate.parse("2022-05-16");

        /* perform test call */

        ResponseEntity<LatestJunoSpotifyStreamsResultsModel> response = apiClient.sendAPIRequest(
            "/v3/juno/spotify/streams/latest?"
                + "country_code=" + countryCode1
                + "&isrc_country_code=" + isrcCountryCode1
                + "&include=" + JunoSpotifyStreamsIncludes.COUNTRY_CODES,
            LatestJunoSpotifyStreamsResultsModel.class
        );

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

        List<LatestJunoSpotifyStreamsResult> items = response.getBody().getItems();

        LatestJunoSpotifyStreamsResult item1 = items.stream()
            .filter(itm -> spotifyTrackId1.equals(itm.getSpotifyTopTrackMeta().getSpotifyTrackId()))
            .findFirst().orElse(null);

        Assertions.assertNotNull(item1);
        Assertions.assertEquals(isrc1, item1.getIsrc());
        Assertions.assertEquals(latestEntryDate, item1.getLatestEntryDate());
        Assertions.assertEquals(productSaleDate, item1.getProductSaleDate());
        Assertions.assertEquals(List.of(countryCode1), item1.getCountryCode());
        Assertions.assertEquals(isrcCountryCode1, item1.getIsrcCountryCode());

        //GRAS track
        Assertions.assertNotNull(item1.getGrasTrackMeta());
        Assertions.assertEquals(grasTrackId1, item1.getGrasTrackMeta().getTrackId());
        Assertions.assertEquals(grasTrackName1, item1.getGrasTrackMeta().getTrackName());

        //Spotify track
        Assertions.assertNotNull(item1.getSpotifyTopTrackMeta());
        Assertions.assertEquals(spotifyTrackId1, item1.getSpotifyTopTrackMeta().getSpotifyTrackId());
        Assertions.assertEquals(spotifyTrackName1, item1.getSpotifyTopTrackMeta().getTrackName());

        //streams metrics
        Assertions.assertNotNull(item1.getMetrics());
        Assertions.assertEquals(streams17DaysTotal, item1.getMetrics().getTotals().getStreamsDays7());
        Assertions.assertEquals(streams814DaysTotal, item1.getMetrics().getTotals().getStreamsDays814());

        Assertions.assertEquals(streamsChange7To14Days, item1.getMetrics().getChange().getStreamsChange7To14Days());
        Assertions.assertEquals(streamsChangePercent7To14Days, item1.getMetrics().getChange().getStreamsChangePercent7To14Days());

        Assertions.assertEquals(streams17DaysLeanBack, item1.getMetrics().getLeanBack().getStreamsDays7());
        Assertions.assertEquals(streams814DaysLeanBack, item1.getMetrics().getLeanBack().getStreamsDays814());

        Assertions.assertEquals(streams17DaysLeanForward, item1.getMetrics().getLeanForward().getStreamsDays7());
        Assertions.assertEquals(streams814DaysLeanForward, item1.getMetrics().getLeanForward().getStreamsDays814());

        Assertions.assertEquals(streams17DaysMale, item1.getMetrics().getDemographics().getMale().getStreamsDays7());
        Assertions.assertEquals(streams814DaysMale, item1.getMetrics().getDemographics().getMale().getStreamsDays814());
        Assertions.assertEquals(streams17DaysFemale, item1.getMetrics().getDemographics().getFemale().getStreamsDays7());
        Assertions.assertEquals(streams814DaysFemale, item1.getMetrics().getDemographics().getFemale().getStreamsDays814());
    }

    @Test
    @SqlScript(scripts = {"/scripts/JunoSpotifyIT/common_test_data_set_1.sql",
        "/scripts/JunoSpotifyIT/getLatestJunoSpotifyStreams_multipleCountries.sql"})
    public void getLatestJunoSpotifyStreams_multipleCountries() {
        //it actually means 'streams country code' here
        String countryCode1 = "us";
        String countryCode2 = "ca";
        String isrcCountryCode1 = "gb";

        String grasTrackId1 = "GRAS_A10328E00000000001";
        String grasTrackName1 = "testGrasTrackName1";

        String spotifyTrackId1 = "testSpotifyTrackId1";
        String spotifyTrackName1 = "tesrSpotifyTrackName1";
        String isrc1 = "USQX91901111";

        long streams17DaysTotal = 5;
        long streams814DaysTotal = 3;
        long streams17DaysLeanBack = 55;
        long streams814DaysLeanBack = 33;
        long streams17DaysLeanForward = 66;
        long streams814DaysLeanForward = 44;
        long streams17DaysMale = 3;
        long streams814DaysMale = 2;
        long streams17DaysFemale = 2;
        long streams814DaysFemale = 1;
        long streamsChange7To14Days = 2;

        double streamsChangePercent7To14Days = 66.67; //streams17DaysTotal (5 * 2) is 66.67% more than streams814DaysTotal (3 * 2)

        LocalDate latestEntryDate = LocalDate.parse("2022-05-16");
        LocalDate productSaleDate = LocalDate.parse("2022-05-16");

        /* perform test call */

        ResponseEntity<LatestJunoSpotifyStreamsResultsModel> response = apiClient.sendAPIRequest(
            "/v3/juno/spotify/streams/latest?"
                + "country_code=" + String.format("%s,%s", countryCode1, countryCode2)
                + "&isrc_country_code=" + isrcCountryCode1
                + "&include=" + JunoSpotifyStreamsIncludes.COUNTRY_CODES,
            LatestJunoSpotifyStreamsResultsModel.class
        );

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

        List<LatestJunoSpotifyStreamsResult> items = response.getBody().getItems();

        LatestJunoSpotifyStreamsResult item1 = items.stream()
            .filter(itm -> spotifyTrackId1.equals(itm.getSpotifyTopTrackMeta().getSpotifyTrackId()))
            .findFirst().orElse(null);

        Assertions.assertNotNull(item1);
        Assertions.assertEquals(isrc1, item1.getIsrc());
        Assertions.assertEquals(latestEntryDate, item1.getLatestEntryDate());
        Assertions.assertEquals(productSaleDate, item1.getProductSaleDate());
        Assertions.assertEquals(List.of(countryCode1, countryCode2), item1.getCountryCode());
        Assertions.assertEquals(isrcCountryCode1, item1.getIsrcCountryCode());

        //GRAS track
        Assertions.assertNotNull(item1.getGrasTrackMeta());
        Assertions.assertEquals(grasTrackId1, item1.getGrasTrackMeta().getTrackId());
        Assertions.assertEquals(grasTrackName1, item1.getGrasTrackMeta().getTrackName());

        //Spotify track
        Assertions.assertNotNull(item1.getSpotifyTopTrackMeta());
        Assertions.assertEquals(spotifyTrackId1, item1.getSpotifyTopTrackMeta().getSpotifyTrackId());
        Assertions.assertEquals(spotifyTrackName1, item1.getSpotifyTopTrackMeta().getTrackName());

        //streams metrics
        Assertions.assertNotNull(item1.getMetrics());
        Assertions.assertEquals(streams17DaysTotal * 2, item1.getMetrics().getTotals().getStreamsDays7());
        Assertions.assertEquals(streams814DaysTotal * 2, item1.getMetrics().getTotals().getStreamsDays814());

        Assertions.assertEquals(streamsChange7To14Days * 2, item1.getMetrics().getChange().getStreamsChange7To14Days());
        Assertions.assertEquals(streamsChangePercent7To14Days, item1.getMetrics().getChange().getStreamsChangePercent7To14Days());

        Assertions.assertEquals(streams17DaysLeanBack * 2, item1.getMetrics().getLeanBack().getStreamsDays7());
        Assertions.assertEquals(streams814DaysLeanBack * 2, item1.getMetrics().getLeanBack().getStreamsDays814());

        Assertions.assertEquals(streams17DaysLeanForward * 2, item1.getMetrics().getLeanForward().getStreamsDays7());
        Assertions.assertEquals(streams814DaysLeanForward * 2, item1.getMetrics().getLeanForward().getStreamsDays814());

        Assertions.assertEquals(streams17DaysMale * 2, item1.getMetrics().getDemographics().getMale().getStreamsDays7());
        Assertions.assertEquals(streams814DaysMale * 2, item1.getMetrics().getDemographics().getMale().getStreamsDays814());
        Assertions.assertEquals(streams17DaysFemale * 2, item1.getMetrics().getDemographics().getFemale().getStreamsDays7());
        Assertions.assertEquals(streams814DaysFemale * 2, item1.getMetrics().getDemographics().getFemale().getStreamsDays814());
    }


    @Test
    @SqlScript(scripts = {"/scripts/JunoSpotifyIT/common_test_data_set_1.sql",
        "/scripts/JunoSpotifyIT/getLatestJunoSpotifyStreams_multipleCountriesPercentChangeFilter.sql"})
    public void getLatestJunoSpotifyStreams_multipleCountriesPercentChangeFilter() {
        //it actually means 'streams country code' here
        String countryCode1 = "us";
        String countryCode2 = "ca";
        String isrcCountryCode1 = "gb";

        String grasTrackId1 = "GRAS_A10328E00000000001";
        String grasTrackName1 = "testGrasTrackName1";

        String spotifyTrackId1 = "testSpotifyTrackId1";
        String spotifyTrackName1 = "tesrSpotifyTrackName1";
        String isrc1 = "USQX91901111";

        long streams17DaysTotal = 11;
        long streams814DaysTotal = 6;
        long streams17DaysLeanBack = 55 * 2;
        long streams814DaysLeanBack = 33 * 2;
        long streams17DaysLeanForward = 66 * 2;
        long streams814DaysLeanForward = 44 * 2;
        long streams17DaysMale = 3 * 2;
        long streams814DaysMale = 2 * 2;
        long streams17DaysFemale = 2 * 2;
        long streams814DaysFemale = 2;
        long streamsChange7To14Days = 2 + 3;

        double streamsChangePercent7To14Days = 83.33; //streams17DaysTotal (6+5) is 83.33% more than streams814DaysTotal (3+3)

        LocalDate latestEntryDate = LocalDate.parse("2022-05-16");
        LocalDate productSaleDate = LocalDate.parse("2022-05-16");

        /* perform test call */

        ResponseEntity<LatestJunoSpotifyStreamsResultsModel> response = apiClient.sendAPIRequest(
            "/v3/juno/spotify/streams/latest?"
                + "country_code=" + String.format("%s,%s", countryCode1, countryCode2)
                + "&isrc_country_code=" + isrcCountryCode1
                + "&percent_change=" + "80"
                + "&include=" + JunoSpotifyStreamsIncludes.COUNTRY_CODES,
            LatestJunoSpotifyStreamsResultsModel.class
        );

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

        List<LatestJunoSpotifyStreamsResult> items = response.getBody().getItems();

        LatestJunoSpotifyStreamsResult item1 = items.stream()
            .filter(itm -> spotifyTrackId1.equals(itm.getSpotifyTopTrackMeta().getSpotifyTrackId()))
            .findFirst().orElse(null);

        Assertions.assertNotNull(item1);
        Assertions.assertEquals(isrc1, item1.getIsrc());
        Assertions.assertEquals(latestEntryDate, item1.getLatestEntryDate());
        Assertions.assertEquals(productSaleDate, item1.getProductSaleDate());
        Assertions.assertEquals(List.of(countryCode1, countryCode2), item1.getCountryCode());
        Assertions.assertEquals(isrcCountryCode1, item1.getIsrcCountryCode());

        //GRAS track
        Assertions.assertNotNull(item1.getGrasTrackMeta());
        Assertions.assertEquals(grasTrackId1, item1.getGrasTrackMeta().getTrackId());
        Assertions.assertEquals(grasTrackName1, item1.getGrasTrackMeta().getTrackName());

        //Spotify track
        Assertions.assertNotNull(item1.getSpotifyTopTrackMeta());
        Assertions.assertEquals(spotifyTrackId1, item1.getSpotifyTopTrackMeta().getSpotifyTrackId());
        Assertions.assertEquals(spotifyTrackName1, item1.getSpotifyTopTrackMeta().getTrackName());

        //streams metrics
        Assertions.assertNotNull(item1.getMetrics());
        Assertions.assertEquals(streams17DaysTotal, item1.getMetrics().getTotals().getStreamsDays7());
        Assertions.assertEquals(streams814DaysTotal, item1.getMetrics().getTotals().getStreamsDays814());

        Assertions.assertEquals(streamsChange7To14Days, item1.getMetrics().getChange().getStreamsChange7To14Days());
        Assertions.assertEquals(streamsChangePercent7To14Days, item1.getMetrics().getChange().getStreamsChangePercent7To14Days());

        Assertions.assertEquals(streams17DaysLeanBack, item1.getMetrics().getLeanBack().getStreamsDays7());
        Assertions.assertEquals(streams814DaysLeanBack, item1.getMetrics().getLeanBack().getStreamsDays814());

        Assertions.assertEquals(streams17DaysLeanForward, item1.getMetrics().getLeanForward().getStreamsDays7());
        Assertions.assertEquals(streams814DaysLeanForward, item1.getMetrics().getLeanForward().getStreamsDays814());

        Assertions.assertEquals(streams17DaysMale, item1.getMetrics().getDemographics().getMale().getStreamsDays7());
        Assertions.assertEquals(streams814DaysMale, item1.getMetrics().getDemographics().getMale().getStreamsDays814());
        Assertions.assertEquals(streams17DaysFemale, item1.getMetrics().getDemographics().getFemale().getStreamsDays7());
        Assertions.assertEquals(streams814DaysFemale, item1.getMetrics().getDemographics().getFemale().getStreamsDays814());
    }
}
