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.UnarchiveRequest;
import com.yandex.direct.api.v5.ads.UnarchiveResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

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.AdsArchiveUnarchiveRequestConverter;
import ru.yandex.direct.api.v5.entity.ads.validation.AdsArchiveUnarchiveRequestValidator;
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.BannerWithSystemFields;
import ru.yandex.direct.core.entity.banner.service.BannerArchiveUnarchiveService;
import ru.yandex.direct.core.entity.feature.service.FeatureService;
import ru.yandex.direct.dbutil.model.ClientId;
import ru.yandex.direct.model.ModelChanges;
import ru.yandex.direct.result.MassResult;
import ru.yandex.direct.tracing.Trace;
import ru.yandex.direct.tracing.TraceProfile;
import ru.yandex.direct.validation.result.ValidationResult;

@Component
@ParametersAreNonnullByDefault
public class UnarchiveAdsDelegate
        extends OperationOnListDelegate<UnarchiveRequest, UnarchiveResponse, ModelChanges<BannerWithSystemFields>,
        Long> {
    private static final Logger logger = LoggerFactory.getLogger(UnarchiveAdsDelegate.class);

    private final BannerArchiveUnarchiveService service;
    private final AdsArchiveUnarchiveRequestValidator requestValidator;
    private final AdsArchiveUnarchiveRequestConverter requestConverter;
    private final ResultConverter resultConverter;

    public UnarchiveAdsDelegate(BannerArchiveUnarchiveService service,
                                ApiAuthenticationSource authentication,
                                AdsArchiveUnarchiveRequestValidator requestValidator,
                                AdsArchiveUnarchiveRequestConverter requestConverter,
                                ResultConverter resultConverter,
                                PpcPropertiesSupport ppcPropertiesSupport,
                                FeatureService featureService) {
        super(ApiPathConverter.forAds(), authentication, ppcPropertiesSupport, featureService);
        this.service = service;
        this.requestValidator = requestValidator;
        this.requestConverter = requestConverter;
        this.resultConverter = resultConverter;
    }

    @Override
    public ValidationResult<UnarchiveRequest, DefectType> validateRequest(UnarchiveRequest externalRequest) {
        logger.debug("validate request: {}", externalRequest);
        try (TraceProfile ignore = Trace.current().profile("ads.unarchive:validateRequest")) {
            return requestValidator.validate(externalRequest);
        }
    }

    @Override
    public List<ModelChanges<BannerWithSystemFields>> convertRequest(UnarchiveRequest externalRequest) {
        logger.debug("convert request: {}", externalRequest);
        try (TraceProfile ignore = Trace.current().profile("ads.unarchive:convertRequest")) {
            return requestConverter.convertUnarchive(externalRequest);
        }
    }

    @Nonnull
    @Override
    public ValidationResult<List<ModelChanges<BannerWithSystemFields>>, DefectType> validateInternalRequest(
            List<ModelChanges<BannerWithSystemFields>> internalRequest) {
        try (TraceProfile ignore = Trace.current().profile("ads.unarchive:validateInternalRequest")) {
            ClientId clientId = auth.getChiefSubclient().getClientId();
            Set<AdGroupType> allowedAdGroupTypes = getAllowedAdGroupTypes();
            return requestValidator.validateInternalRequest(clientId, internalRequest, allowedAdGroupTypes);
        }
    }

    @Override
    public ApiMassResult<Long> processList(List<ModelChanges<BannerWithSystemFields>> validItems) {
        try (TraceProfile ignore = Trace.current().profile("ads.unarchive:processList")) {
            MassResult<Long> result = service.archiveUnarchiveBanners(getClientId(), getOperatorUid(), validItems,
                    /* archive = */ false);
            return resultConverter.toApiMassResult(result);
        }
    }

    @Override
    public UnarchiveResponse convertResponse(ApiResult<List<ApiResult<Long>>> result) {
        logger.debug("convert result: {}", result);
        try (TraceProfile ignore = Trace.current().profile("ads.unarchive:convertResponse")) {
            return new UnarchiveResponse().withUnarchiveResults(resultConverter.toActionResults(result, apiPathConverter));
        }
    }

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

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