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

import java.util.List;
import java.util.Set;

import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;

import com.yandex.direct.api.v5.ads.AddRequest;
import com.yandex.direct.api.v5.ads.AddResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import ru.yandex.direct.api.v5.common.ApiPathConverter;
import ru.yandex.direct.api.v5.converter.ResultConverter;
import ru.yandex.direct.api.v5.entity.OperationOnListDelegate;
import ru.yandex.direct.api.v5.entity.ads.converter.AdsAddRequestConverter;
import ru.yandex.direct.api.v5.entity.ads.validation.AdsAddRequestValidator;
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.common.db.PpcPropertiesSupport;
import ru.yandex.direct.core.entity.adgroup.model.AdGroupType;
import ru.yandex.direct.core.entity.banner.model.BannerWithAdGroupId;
import ru.yandex.direct.core.entity.banner.service.BannersAddOperationFactory;
import ru.yandex.direct.core.entity.feature.service.FeatureService;
import ru.yandex.direct.dbutil.model.ClientId;
import ru.yandex.direct.feature.FeatureName;
import ru.yandex.direct.result.MassResult;
import ru.yandex.direct.validation.result.ValidationResult;

@Service
@ParametersAreNonnullByDefault
public class AddAdsDelegate
        extends OperationOnListDelegate<AddRequest, AddResponse, BannerWithAdGroupId, Long> {

    private static final Logger logger = LoggerFactory.getLogger(AddAdsDelegate.class);

    private final AdsAddRequestValidator requestValidator;
    private final AdsAddRequestConverter requestConverter;
    private final ResultConverter resultConverter;
    private final BannersAddOperationFactory bannersAddOperationFactory;
    private final FeatureService featureService;

    @Autowired
    public AddAdsDelegate(
            ApiAuthenticationSource auth,
            AdsAddRequestValidator requestValidator,
            AdsAddRequestConverter requestConverter,
            ResultConverter resultConverter,
            PpcPropertiesSupport ppcPropertiesSupport,
            FeatureService featureService,
            BannersAddOperationFactory bannersAddOperationFactory) {
        super(ApiPathConverter.forAds(), auth, ppcPropertiesSupport, featureService);
        this.requestValidator = requestValidator;
        this.requestConverter = requestConverter;
        this.resultConverter = resultConverter;
        this.bannersAddOperationFactory = bannersAddOperationFactory;
        this.featureService = featureService;
    }

    @Override
    public ValidationResult<AddRequest, DefectType> validateRequest(AddRequest externalRequest) {
        logger.debug("validate request: {}", externalRequest);
        ClientId clientId = auth.getChiefSubclient().getClientId();
        boolean smartNoCreatives = featureService.isEnabledForClientId(clientId, FeatureName.SMART_NO_CREATIVES);
        return requestValidator.validate(externalRequest, auth.isServicesApplication(), auth.isDisplayUrlTextAllowed(),
                auth.isLeadformAttributesAllowed(), smartNoCreatives);
    }

    @Override
    public List<BannerWithAdGroupId> convertRequest(AddRequest externalRequest) {
        logger.debug("convert request: {}", externalRequest);
        return requestConverter.convert(externalRequest);
    }

    @Override
    @Nonnull
    public ValidationResult<List<BannerWithAdGroupId>, DefectType> validateInternalRequest(
            List<BannerWithAdGroupId> internalRequest) {
        Set<AdGroupType> allowedAdGroupTypes = getAllowedAdGroupTypes();
        String allowedAdTypes = getAllowedAdTypes();
        ClientId clientId = auth.getChiefSubclient().getClientId();
        return requestValidator.validateInternalRequest(clientId, internalRequest, allowedAdGroupTypes, allowedAdTypes);
    }

    @Override
    public ApiMassResult<Long> processList(List<BannerWithAdGroupId> validItems) {
        logger.debug("process request: {}", validItems);

        MassResult<Long> result = bannersAddOperationFactory
                .createAddOperation(validItems, getClientId(), getOperatorUid(), true, true)
                .prepareAndApply();
        return resultConverter.toApiMassResult(result);
    }

    @Override
    public AddResponse convertResponse(ApiResult<List<ApiResult<Long>>> result) {
        logger.debug("convert result: {}", result);
        return new AddResponse().withAddResults(resultConverter.toActionResults(result, apiPathConverter));
    }

    private ClientId getClientId() {
        return auth.getChiefSubclient().getClientId();
    }

    private Long getOperatorUid() {
        return auth.getOperator().getUid();
    }
}
