package ru.yandex.direct.api.v5.entity.keywordbids.service;

import java.util.function.Function;

import javax.annotation.ParametersAreNonnullByDefault;

import com.yandex.direct.api.v5.keywordbids.GetRequest;
import com.yandex.direct.api.v5.keywordbids.KeywordBidsSelectionCriteria;
import one.util.streamex.StreamEx;
import org.springframework.stereotype.Service;

import ru.yandex.direct.api.v5.common.validation.GetRequestGeneralValidator;
import ru.yandex.direct.api.v5.validation.DefectType;
import ru.yandex.direct.validation.builder.Constraint;
import ru.yandex.direct.validation.builder.ItemValidationBuilder;
import ru.yandex.direct.validation.result.MappingPathConverter;
import ru.yandex.direct.validation.result.PathConverter;
import ru.yandex.direct.validation.result.ValidationResult;

import static java.util.Arrays.asList;
import static ru.yandex.direct.api.v5.validation.DefectTypes.maxElementsInSelection;
import static ru.yandex.direct.api.v5.validation.DefectTypes.missedParamsInSelection;
import static ru.yandex.direct.api.v5.validation.constraints.Constraints.maxListSize;

@ParametersAreNonnullByDefault
@Service
public class GetKeywordBidsValidationService {

    private static final int GET_KEYWORD_IDS_LIMIT = 10_000;
    private static final int GET_ADGROUP_IDS_LIMIT = 1000;
    private static final int GET_CAMPAIGN_IDS_LIMIT = 10;
    public static final String SELECTION_CRITERIA_PATH_KEY = "SelectionCriteria";
    public static final String KEYWORD_IDS_PATH_KEY = "KeywordIds";
    public static final String AD_GROUP_IDS_PATH_KEY = "AdGroupIds";
    public static final String CAMPAIGN_IDS_PATH_KEY = "CampaignIds";
    private static final String PAGE_PATH_KEY = "Page";
    private static final String PAGE_LIMIT_PATH_KEY = "Limit";
    private static final String PAGE_OFFSET_PATH_KEY = "Offset";

    public PathConverter pathConverter() {
        return MappingPathConverter.builder(GetKeywordBidsValidationService.class, "GetKeywordBidsValidator")
                .add(StreamEx.of(SELECTION_CRITERIA_PATH_KEY, KEYWORD_IDS_PATH_KEY,
                        AD_GROUP_IDS_PATH_KEY, CAMPAIGN_IDS_PATH_KEY,
                        PAGE_PATH_KEY, PAGE_LIMIT_PATH_KEY, PAGE_OFFSET_PATH_KEY)
                        .mapToEntry(Function.identity()).toMap())
                .build();
    }

    public ValidationResult<GetRequest, DefectType> validate(GetRequest internalRequest) {
        ItemValidationBuilder<GetRequest, DefectType> ivb = ItemValidationBuilder.of(internalRequest);
        KeywordBidsSelectionCriteria selectionCriteria = internalRequest.getSelectionCriteria();
        ItemValidationBuilder<KeywordBidsSelectionCriteria, DefectType> selectionCriteriaValidation =
                ivb.item(selectionCriteria, SELECTION_CRITERIA_PATH_KEY);

        // проверка offset + limit
        ivb.checkBy(GetRequestGeneralValidator::validateRequestWithDefectTypes);

        selectionCriteriaValidation.check(atLeastOneRequiredParamPresent());

        selectionCriteriaValidation.item(selectionCriteria.getKeywordIds(), KEYWORD_IDS_PATH_KEY)
                .check(maxListSize(GET_KEYWORD_IDS_LIMIT), maxElementsInSelection(GET_KEYWORD_IDS_LIMIT));
        selectionCriteriaValidation.item(selectionCriteria.getAdGroupIds(), AD_GROUP_IDS_PATH_KEY)
                .check(maxListSize(GET_ADGROUP_IDS_LIMIT), maxElementsInSelection(GET_ADGROUP_IDS_LIMIT));
        selectionCriteriaValidation.item(selectionCriteria.getCampaignIds(), CAMPAIGN_IDS_PATH_KEY)
                .check(maxListSize(GET_CAMPAIGN_IDS_LIMIT), maxElementsInSelection(GET_CAMPAIGN_IDS_LIMIT));

        return ivb.getResult();
    }

    private Constraint<KeywordBidsSelectionCriteria, DefectType> atLeastOneRequiredParamPresent() {
        return Constraint.fromPredicate(
                bsc -> !bsc.getKeywordIds().isEmpty() || !bsc.getAdGroupIds().isEmpty()
                        || !bsc.getCampaignIds().isEmpty(),
                missedParamsInSelection(
                        String.join(", ",
                                asList(KEYWORD_IDS_PATH_KEY, AD_GROUP_IDS_PATH_KEY, CAMPAIGN_IDS_PATH_KEY))));
    }
}
