package ru.yandex.direct.api.v5.entity.keywords.delegate;

import java.util.List;

import javax.annotation.Nullable;

import com.yandex.direct.api.v5.general.ActionResult;
import com.yandex.direct.api.v5.keywords.SuspendRequest;
import com.yandex.direct.api.v5.keywords.SuspendResponse;
import org.springframework.stereotype.Service;

import ru.yandex.direct.api.v5.common.validation.DefectPresentationsHolder;
import ru.yandex.direct.api.v5.converter.ResultConverter;
import ru.yandex.direct.api.v5.entity.BaseApiServiceDelegate;
import ru.yandex.direct.api.v5.entity.keywords.KeywordsDefectTypes;
import ru.yandex.direct.api.v5.entity.keywords.container.UpdateInputItem;
import ru.yandex.direct.api.v5.entity.keywords.converter.KeywordsSuspendRequestConverter;
import ru.yandex.direct.api.v5.entity.keywords.validation.KeywordsIdsCriteriaValidator;
import ru.yandex.direct.api.v5.result.ApiResult;
import ru.yandex.direct.api.v5.security.ApiAuthenticationSource;
import ru.yandex.direct.api.v5.validation.DefectType;
import ru.yandex.direct.core.entity.keyword.model.Keyword;
import ru.yandex.direct.core.entity.keyword.service.validation.KeywordDefectIds;
import ru.yandex.direct.core.entity.user.model.ApiUser;
import ru.yandex.direct.validation.builder.ItemValidationBuilder;
import ru.yandex.direct.validation.builder.When;
import ru.yandex.direct.validation.defect.ids.CollectionDefectIds;
import ru.yandex.direct.validation.result.MappingPathConverter;
import ru.yandex.direct.validation.result.PathConverter;
import ru.yandex.direct.validation.result.ValidationResult;

import static ru.yandex.direct.api.v5.validation.constraints.Constraints.notNull;
import static ru.yandex.direct.utils.FunctionalUtils.mapList;

@Service
public class SuspendKeywordsDelegate
        extends BaseApiServiceDelegate<SuspendRequest, SuspendResponse, List<UpdateInputItem>, ApiResult<Long>> {
    private static final DefectPresentationsHolder KEYWORDS_SUSPEND_CUSTOM_DEFECT_PRESENTATIONS =
            DefectPresentationsHolder.builderWithFallback(KeywordsUpdater.KEYWORDS_UPDATER_CUSTOM_DEFECT_PRESENTATIONS)
                    .register(KeywordDefectIds.Gen.AD_GROUP_NOT_FOUND,
                            KeywordsDefectTypes.keywordNotFound())
                    .register(CollectionDefectIds.Gen.MUST_NOT_CONTAIN_DUPLICATED_OBJECTS,
                            KeywordsDefectTypes.warningDuplicatedId())
                    .build();

    private static final PathConverter SUSPEND_KEYWORDS_PATH_CONVERTER =
            MappingPathConverter.builder(SuspendKeywordsDelegate.class, "capitalize")
                    .ignore(Keyword.ID.name())
                    .ignore(Keyword.AD_GROUP_ID.name())
                    .ignore(Keyword.PHRASE.name())
                    .ignore(Keyword.HREF_PARAM1.name())
                    .ignore(Keyword.HREF_PARAM2.name())
                    .build();

    private final ResultConverter resultConverter;
    private final KeywordsIdsCriteriaValidator idsCriteriaValidator;
    private final KeywordsSuspendRequestConverter keywordsSuspendRequestConverter;
    private final KeywordsUpdater keywordsUpdater;

    public SuspendKeywordsDelegate(ApiAuthenticationSource auth,
                                   ResultConverter resultConverter,
                                   KeywordsIdsCriteriaValidator idsCriteriaValidator,
                                   KeywordsSuspendRequestConverter keywordsSuspendRequestConverter,
                                   KeywordsUpdater keywordsUpdater) {
        super(SUSPEND_KEYWORDS_PATH_CONVERTER, auth);
        this.resultConverter = resultConverter;
        this.idsCriteriaValidator = idsCriteriaValidator;
        this.keywordsSuspendRequestConverter = keywordsSuspendRequestConverter;
        this.keywordsUpdater = keywordsUpdater;
    }

    @Nullable
    @Override
    public ValidationResult<SuspendRequest, DefectType> validateRequest(SuspendRequest externalRequest) {
        ItemValidationBuilder<SuspendRequest, DefectType> vb = ItemValidationBuilder.of(externalRequest);
        vb.item(externalRequest.getSelectionCriteria(),
                SuspendRequest.PropInfo.SELECTION_CRITERIA.schemaName.getLocalPart())
                .check(notNull())
                .checkBy(idsCriteriaValidator::validate, When.isValid());
        return vb.getResult();
    }

    @Override
    public List<UpdateInputItem> convertRequest(SuspendRequest externalRequest) {
        ApiUser targetUser = auth.getChiefSubclient();
        return keywordsSuspendRequestConverter.convertRequest(externalRequest, targetUser.getClientId());
    }

    @Override
    public ApiResult<List<ApiResult<Long>>> processRequest(List<UpdateInputItem> internalRequest) {
        return keywordsUpdater.doUpdate(internalRequest, true, true, KEYWORDS_SUSPEND_CUSTOM_DEFECT_PRESENTATIONS);
    }

    @Override
    public SuspendResponse convertResponse(ApiResult<List<ApiResult<Long>>> result) {
        List<ActionResult> updateResults = mapList(result.getResult(), r -> resultConverter.toActionResult(
                r, apiPathConverter, ActionResult::new, ActionResult::setId));
        return new SuspendResponse().withSuspendResults(updateResults);
    }
}
