package io.delphiplatform.api.v3.view;

import org.hibernate.validator.constraints.ParameterScriptAssert;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import java.time.LocalDate;
import java.util.Set;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Pattern;

import io.delphiplatform.api.v3.constant.ApplicationConstants;
import io.delphiplatform.api.v3.model.JunoSpotifyStreamsIncludes;
import io.delphiplatform.api.v3.model.SortOrder;
import io.delphiplatform.api.v3.model.datahealth.DspDataImportReport;
import io.delphiplatform.api.v3.model.spotify.LatestJunoSpotifyStreamsResults;
import io.delphiplatform.api.v3.validation.ExactMatchesForSingleValue;
import io.delphiplatform.api.v3.view.interceptor.OnlyDeclaredParams;
import io.delphiplatform.api.v3.view.util.Params;
import lombok.NonNull;

import static io.delphiplatform.api.v3.constant.ApplicationConstants.COUNTRY_CODE_PATTERN;
import static io.delphiplatform.api.v3.constant.ApplicationConstants.MAX_PAGE_SIZE;

@Validated
public interface JunoSpotifyApi {

    ResponseEntity<LatestJunoSpotifyStreamsResults> getLatestJunoSpotifyStreams(@NonNull Params params);

    ResponseEntity<DspDataImportReport> getJunoSpotifyDataStatusDaily();

    @ParameterScriptAssert.List({
        @ParameterScriptAssert(lang = "groovy",
            message = ApplicationConstants.ERROR_MESSAGE_COUNTRY_CODE_WORLDWIDE_SINGLE_VALUE,
            script = ApplicationConstants.SCRIPT_COUNTRY_CODE_SINGLE_WORLDWIDE
        ),
        @ParameterScriptAssert(lang = "groovy",
            message = ApplicationConstants.ERROR_MESSAGE_MIN_MAX_SELL_DATES,
            script = ApplicationConstants.SCRIPT_PRODUCT_SALE_DATES_IN_ORDER
        )
    })
    @OnlyDeclaredParams
    @RequestMapping(value = "/juno/spotify/streams/latest",
        produces = {"application/json"},
        method = RequestMethod.GET)
    default ResponseEntity<LatestJunoSpotifyStreamsResults> getLatestJunoSpotifyStreams(
        @RequestParam(value = "include", required = false) Set<JunoSpotifyStreamsIncludes> include,
        @RequestParam(value = "country_code")
            Set<@Pattern(regexp = COUNTRY_CODE_PATTERN) String> countryCode,
        @RequestParam(value = "isrc_country_code", required = false)
            Set<@Pattern(regexp = COUNTRY_CODE_PATTERN) String> isrcCountryCode,
        @RequestParam(value = "percent_change", required = false) Double percentChange,
        @RequestParam(value = "min_product_sale_date", required = false)
        @DateTimeFormat(iso = ISO.DATE) LocalDate minProductSaleDate,
        @RequestParam(value = "max_product_sale_date", required = false)
        @DateTimeFormat(iso = ISO.DATE) LocalDate maxProductSaleDate,
        @ExactMatchesForSingleValue(message = ApplicationConstants.ERROR_MESSAGE_SORT_BY_PARAMETER, anyOf = {
            "streams_days_7", "streams_days_8_14", "streams_change_7_to_14_days", "streams_change_7_to_14_days_lean_back",
            "streams_change_7_to_14_days_lean_forward", "streams_change_percent_7_to_14_days", "streams_change_percent_7_to_14_days_lean_back",
            "streams_change_percent_7_to_14_days_lean_forward"

        })
        @RequestParam(value = "sort_by", required = false) String sortBy,
        @RequestParam(value = "sort_order", required = false, defaultValue = "desc") SortOrder sortOrder,
        @Min(0) @Max(MAX_PAGE_SIZE) @RequestParam(value = "limit", required = false) Integer limit,
        @Min(0) @RequestParam(value = "offset", required = false) Integer offset
    ) {
        return getLatestJunoSpotifyStreams(Params.builder()
            .junoSpotifyStreamsIncludes(include)
            .streamsCountryCode(countryCode)
            .countryCode(isrcCountryCode)
            .percentChange(percentChange)
            .startDate(minProductSaleDate)
            .endDate(maxProductSaleDate)
            .sortBy(sortBy)
            .sortOrder(sortOrder)
            .limit(limit)
            .offset(offset)
            .build());
    }

    @RequestMapping(value = "/juno/spotify/status/daily",
        produces = {"application/json"},
        method = RequestMethod.GET)
    default ResponseEntity<DspDataImportReport> getJunoSpotifyStreamsDataStatusDaily() {
        return getJunoSpotifyDataStatusDaily();
    }
}
