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

import java.util.List;

import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;

import com.yandex.direct.api.v5.dynamictextadtargets.SetBidsRequest;
import com.yandex.direct.api.v5.dynamictextadtargets.SetBidsResponse;
import com.yandex.direct.api.v5.general.SetBidsActionResult;
import org.springframework.stereotype.Component;

import ru.yandex.direct.api.v5.common.ApiPathConverter;
import ru.yandex.direct.api.v5.common.validation.DefectPresentationsHolder;
import ru.yandex.direct.api.v5.converter.ResultConverter;
import ru.yandex.direct.api.v5.entity.OperationOnListDelegate;
import ru.yandex.direct.api.v5.entity.dynamictextadtargets.DynamicAdTargetsDefectTypes;
import ru.yandex.direct.api.v5.entity.dynamictextadtargets.converter.SetBidsRequestConverter;
import ru.yandex.direct.api.v5.entity.dynamictextadtargets.validation.DynamicTextAdTargetsDefectPresentations;
import ru.yandex.direct.api.v5.entity.dynamictextadtargets.validation.DynamicTextAdTargetsSetBidsRequestValidator;
import ru.yandex.direct.api.v5.result.ApiMassResult;
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.bids.container.SetBidItem;
import ru.yandex.direct.core.entity.bids.validation.BidsDefects;
import ru.yandex.direct.core.entity.dynamictextadtarget.service.DynamicTextAdTargetSetBidsService;
import ru.yandex.direct.dbutil.model.ClientId;
import ru.yandex.direct.validation.result.DefectIds;
import ru.yandex.direct.validation.result.ValidationResult;

import static ru.yandex.direct.api.v5.entity.dynamictextadtargets.validation.DynamicTextAdTargetsDefectPresentations.DYNAMIC_TEXT_AD_TARGETS_IDS_MAPPING;
import static ru.yandex.direct.api.v5.validation.DefectTypes.possibleOnlyOneField;
import static ru.yandex.direct.api.v5.validation.DefectTypes.requiredAtLeastOneOfFields;
import static ru.yandex.direct.utils.FunctionalUtils.mapList;

@ParametersAreNonnullByDefault
@Component
public class SetBidsDynamicTextAdTargetsDelegate extends OperationOnListDelegate<SetBidsRequest, SetBidsResponse,
        SetBidItem, SetBidItem> {

    public static final DefectPresentationsHolder CUSTOM_SET_BIDS_PRESENTATION =
            DefectPresentationsHolder
                    .builderWithFallback(DynamicTextAdTargetsDefectPresentations.DEFECT_PRESENTATIONS_HOLDER)
                    .register(DefectIds.OBJECT_NOT_FOUND,
                            DynamicAdTargetsDefectTypes.dynamicTextAdTargetsConditionNotFound())
                    .register(DefectIds.MUST_BE_VALID_ID,
                            DynamicAdTargetsDefectTypes.invalidIdInFieldForSetBids())
                    .register(BidsDefects.ModelDefects.POSSIBLE_ONLY_ONE_FIELD,
                            t -> possibleOnlyOneField(DYNAMIC_TEXT_AD_TARGETS_IDS_MAPPING.getBidsFields(t)))
                    .register(BidsDefects.ModelDefects.ONE_OF_FIELDS_SHOULD_BE_SPECIFIED,
                            t -> requiredAtLeastOneOfFields(DYNAMIC_TEXT_AD_TARGETS_IDS_MAPPING.getBidsFields(t)))
                    .build();


    private final DynamicTextAdTargetsSetBidsRequestValidator requestValidator;
    private final ResultConverter resultConverter;
    private final SetBidsRequestConverter requestConverter;
    private final DynamicTextAdTargetSetBidsService service;


    public SetBidsDynamicTextAdTargetsDelegate(ApiAuthenticationSource auth,
                                               DynamicTextAdTargetsSetBidsRequestValidator requestValidator,
                                               ResultConverter resultConverter,
                                               SetBidsRequestConverter requestConverter,
                                               DynamicTextAdTargetSetBidsService service) {
        super(ApiPathConverter.forDynamicTextAdTargets(), auth);
        this.requestValidator = requestValidator;
        this.resultConverter = resultConverter;
        this.requestConverter = requestConverter;
        this.service = service;
    }

    @Nullable
    @Override
    public ValidationResult<SetBidsRequest, DefectType> validateRequest(SetBidsRequest externalRequest) {
        return requestValidator.validate(externalRequest);
    }

    @Override
    public List<SetBidItem> convertRequest(SetBidsRequest externalRequest) {
        return requestConverter.convertSetBidsRequest(externalRequest);
    }

    @Override
    public ApiMassResult<SetBidItem> processList(List<SetBidItem> validItems) {
        Long operatorUid = auth.getOperator().getUid();
        ClientId clientId = auth.getChiefSubclient().getClientId();
        return resultConverter
                .toApiMassResult(service.setBids(clientId, operatorUid, validItems), CUSTOM_SET_BIDS_PRESENTATION);
    }

    @Override
    public SetBidsResponse convertResponse(ApiResult<List<ApiResult<SetBidItem>>> result) {
        List<SetBidsActionResult> setBidsActionResults =
                mapList(result.getResult(), r -> resultConverter.convertToSetBidsActionResult(r, apiPathConverter));
        return new SetBidsResponse().withSetBidsResults(setBidsActionResults);
    }
}
