package ru.yandex.autotests.direct.api.ads.update.textad.calloutsetting;

import java.util.Arrays;
import java.util.List;

import com.yandex.direct.api.v5.ads.AddResponse;
import com.yandex.direct.api.v5.general.OperationEnum;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;

import ru.yandex.aqua.annotations.project.Aqua;
import ru.yandex.autotests.direct.api.ads.AdsFeatures;
import ru.yandex.autotests.direct.api.ads.AdsLogins;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.BannersAdditionsAdditionsType;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.BannersAdditionsRecord;
import ru.yandex.autotests.direct.db.steps.DirectJooqDbSteps;
import ru.yandex.autotests.directapi.apiclient.config.Semaphore;
import ru.yandex.autotests.directapi.apiclient.errors.Api5ErrorDetails;
import ru.yandex.autotests.directapi.model.api5.adextensions.AdExtensionAddItemMap;
import ru.yandex.autotests.directapi.model.api5.adextensiontypes.AdExtensionSettingItemMap;
import ru.yandex.autotests.directapi.model.api5.adextensiontypes.AdExtensionSettingMap;
import ru.yandex.autotests.directapi.model.api5.adextensiontypes.CalloutMap;
import ru.yandex.autotests.directapi.model.api5.ads.AdAddItemMap;
import ru.yandex.autotests.directapi.model.api5.ads.AdUpdateItemMap;
import ru.yandex.autotests.directapi.model.api5.ads.AddRequestMap;
import ru.yandex.autotests.directapi.model.api5.ads.TextAdAddMap;
import ru.yandex.autotests.directapi.model.api5.ads.TextAdUpdateMap;
import ru.yandex.autotests.directapi.model.api5.ads.UpdateRequestMap;
import ru.yandex.autotests.directapi.model.api5.general.ExpectedResult;
import ru.yandex.autotests.directapi.model.api5.general.Notification;
import ru.yandex.autotests.directapi.rules.ApiSteps;
import ru.yandex.autotests.directapi.rules.Trashman;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Issue;
import ru.yandex.qatools.hazelcast.SemaphoreRule;

import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import static org.apache.commons.lang3.StringUtils.capitalize;
import static ru.yandex.autotests.direct.db.utils.JooqRecordListDifferMatcher.recordsDiffer;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;

/**
 * Created by pavryabov on 17.03.16.
 * https://st.yandex-team.ru/TESTIRT-8642
 */
@Aqua.Test
@Features(AdsFeatures.UPDATE)
@Description("Проверка обновления уточнений с разными операциями в одном запросе")
@Issue("https://st.yandex-team.ru/DIRECT-50726")
public class UpdateCalloutsDifferentOperationsTest {

    @ClassRule
    public static ApiSteps api = new ApiSteps().version(104).as(AdsLogins.CLIENT);
    private static DirectJooqDbSteps jooqDbSteps;

    @ClassRule
    public static SemaphoreRule semaphore = Semaphore.getSemaphore();

    @Rule
    public Trashman trasher = new Trashman(api);

    private static Long adExtensionId;
    private static Long adExtensionIdElse;
    private static Long adGroupId;


    @BeforeClass
    public static void initTest() {
        api.userSteps.clientFakeSteps().fakeClearClientSpentUnits(AdsLogins.CLIENT);
        jooqDbSteps = api.userSteps.getDirectJooqDbSteps().useShardForLogin(AdsLogins.CLIENT);
        Long campaignId = api.userSteps.campaignSteps().addDefaultTextCampaign();
        adGroupId = api.userSteps.adGroupsSteps().addDefaultGroup(campaignId);
        adExtensionId = api.userSteps.adExtensionsSteps().addCalloutWithText(randomAlphabetic(15));
        adExtensionIdElse = api.userSteps.adExtensionsSteps().addCalloutWithText(randomAlphabetic(15));
    }

    @Test
    public void addNewCalloutAndRemoveOld() {
        Long adId = api.userSteps.adsSteps().addAd(new AdAddItemMap()
                .withAdGroupId(adGroupId)
                .withTextAd(new TextAdAddMap()
                        .defaultTextAd()
                        .withAdExtensionIds(adExtensionId)));
        api.userSteps.adsSteps().shouldGetResultOnUpdate(new UpdateRequestMap()
                        .withAds(new AdUpdateItemMap()
                                .withId(adId)
                                .withTextAd(new TextAdUpdateMap()
                                        .defaultAd()
                                        .withCalloutSetting(new AdExtensionSettingMap()
                                                .withAdExtensions(new AdExtensionSettingItemMap()
                                                                .withAdExtensionId(adExtensionIdElse)
                                                                .withOperation(OperationEnum.ADD),
                                                        new AdExtensionSettingItemMap()
                                                                .withAdExtensionId(adExtensionId)
                                                                .withOperation(OperationEnum.REMOVE))))),
                ExpectedResult.success(adId));

        List<BannersAdditionsRecord> bannersAdditions =
                jooqDbSteps.bannerAdditionsSteps().getBannersAdditionsRecordsByBid(adId);
        BannersAdditionsRecord expectedBannersAdditions =
                new BannersAdditionsRecord(adId, adExtensionIdElse, BannersAdditionsAdditionsType.callout, (short) 1);

        assertThat("дополнения правильно привязались к объявлению",
                bannersAdditions, recordsDiffer(Arrays.asList(expectedBannersAdditions)));
    }

    @Test
    public void addAndRemoveSameCallout() {
        Long adId = api.userSteps.adsSteps().addAd(new AdAddItemMap()
                .withAdGroupId(adGroupId)
                .withTextAd(new TextAdAddMap()
                        .defaultTextAd()
                        .withAdExtensionIds(adExtensionId)));
        api.userSteps.adsSteps().shouldGetResultOnUpdate(new UpdateRequestMap()
                        .withAds(new AdUpdateItemMap()
                                .withId(adId)
                                .withTextAd(new TextAdUpdateMap()
                                        .defaultAd()
                                        .withCalloutSetting(new AdExtensionSettingMap()
                                                .withAdExtensions(new AdExtensionSettingItemMap()
                                                                .withAdExtensionId(adExtensionId)
                                                                .withOperation(OperationEnum.ADD),
                                                        new AdExtensionSettingItemMap()
                                                                .withAdExtensionId(adExtensionId)
                                                                .withOperation(OperationEnum.REMOVE))))),
                ExpectedResult.errors(new Notification(9802, Api5ErrorDetails.VALUE_CANNOT_BE_PRESENT_IN_FIELD_MORE_THAN_ONCE,
                        adExtensionId,
                        capitalize(TextAdUpdateMap.CALLOUT_SETTING) + "." +
                                capitalize(AdExtensionSettingMap.AD_EXTENSIONS) + "." +
                                capitalize(AdExtensionSettingItemMap.AD_EXTENSION_ID))));
    }

    @Test
    public void addCalloutToAdWithMaxAmountOfCalloutsAndRemoveOneOfThem() {
        AdExtensionAddItemMap[] adExtensionAddItemMaps =
                new AdExtensionAddItemMap[TextAdAddMap.MAX_AD_EXTENSION_IDS_IN_AD];
        for (int i = 0; i < TextAdAddMap.MAX_AD_EXTENSION_IDS_IN_AD; i++) {
            adExtensionAddItemMaps[i] = new AdExtensionAddItemMap()
                    .withCallout(new CalloutMap()
                            .withCalloutText(randomAlphabetic(15)));
        }
        List<Long> adExtensionIds = api.userSteps.adExtensionsSteps().addAdExtensions(adExtensionAddItemMaps);
        AddResponse response = api.userSteps.adsSteps().shouldGetResultOnAdd(new AddRequestMap()
                        .withAds(new AdAddItemMap()
                                .withTextAd(new TextAdAddMap()
                                        .defaultTextAd()
                                        .withAdExtensionIds(adExtensionIds.toArray(new Long[]{})))
                                .withAdGroupId(adGroupId)),
                ExpectedResult.success());
        Long id = response.getAddResults().get(0).getId();
        api.userSteps.adsSteps().shouldGetResultOnUpdate(new UpdateRequestMap()
                        .withAds(new AdUpdateItemMap()
                                .withId(id)
                                .withTextAd(new TextAdUpdateMap()
                                        .withCalloutSetting(new AdExtensionSettingMap()
                                                .withAdExtensions(new AdExtensionSettingItemMap()
                                                                .withAdExtensionId(adExtensionId)
                                                                .withOperation(OperationEnum.ADD),
                                                        new AdExtensionSettingItemMap()
                                                                .withAdExtensionId(adExtensionIds.get(0))
                                                                .withOperation(OperationEnum.REMOVE))))),
                ExpectedResult.success(id));
    }

    @Test
    public void addAlreadyLinkedCalloutAndRemoveNorLinkedCallout() {
        Long adId = api.userSteps.adsSteps().addAd(new AdAddItemMap()
                .withAdGroupId(adGroupId)
                .withTextAd(new TextAdAddMap()
                        .defaultTextAd()
                        .withAdExtensionIds(adExtensionId)));
        api.userSteps.adsSteps().shouldGetResultOnUpdate(new UpdateRequestMap()
                        .withAds(new AdUpdateItemMap()
                                .withId(adId)
                                .withTextAd(new TextAdUpdateMap()
                                        .defaultAd()
                                        .withCalloutSetting(new AdExtensionSettingMap()
                                                .withAdExtensions(new AdExtensionSettingItemMap()
                                                                .withAdExtensionId(adExtensionId)
                                                                .withOperation(OperationEnum.ADD),
                                                        new AdExtensionSettingItemMap()
                                                                .withAdExtensionId(adExtensionIdElse)
                                                                .withOperation(OperationEnum.REMOVE))))),
                ExpectedResult.warnings(adId,
                        new Notification(10170, Api5ErrorDetails.AD_EXTENSION_ALREADY_LINKED, adExtensionId),
                        new Notification(10171, Api5ErrorDetails.AD_EXTENSION_NOT_LINKED, adExtensionIdElse)));
    }

    @Test
    public void addAndSetInOneRequest() {
        Long adId = api.userSteps.adsSteps().addDefaultTextAd(adGroupId);
        api.userSteps.adsSteps().shouldGetResultOnUpdate(new UpdateRequestMap()
                        .withAds(new AdUpdateItemMap()
                                .withId(adId)
                                .withTextAd(new TextAdUpdateMap()
                                        .defaultAd()
                                        .withCalloutSetting(new AdExtensionSettingMap()
                                                .withAdExtensions(new AdExtensionSettingItemMap()
                                                                .withAdExtensionId(adExtensionId)
                                                                .withOperation(OperationEnum.ADD),
                                                        new AdExtensionSettingItemMap()
                                                                .withAdExtensionId(adExtensionIdElse)
                                                                .withOperation(OperationEnum.SET))))),
                ExpectedResult.errors(
                        new Notification(4006, Api5ErrorDetails.CANNOT_SPECIFY_DIFFERENT_OPERATIONS_IN_ONE_REQUEST)));
    }

    @Test
    public void removeAndSetInOneRequest() {
        Long adId = api.userSteps.adsSteps().addDefaultTextAd(adGroupId);
        api.userSteps.adsSteps().shouldGetResultOnUpdate(new UpdateRequestMap()
                        .withAds(new AdUpdateItemMap()
                                .withId(adId)
                                .withTextAd(new TextAdUpdateMap()
                                        .defaultAd()
                                        .withCalloutSetting(new AdExtensionSettingMap()
                                                .withAdExtensions(new AdExtensionSettingItemMap()
                                                                .withAdExtensionId(adExtensionId)
                                                                .withOperation(OperationEnum.SET),
                                                        new AdExtensionSettingItemMap()
                                                                .withAdExtensionId(adExtensionIdElse)
                                                                .withOperation(OperationEnum.REMOVE))))),
                ExpectedResult.errors(
                        new Notification(4006, Api5ErrorDetails.CANNOT_SPECIFY_DIFFERENT_OPERATIONS_IN_ONE_REQUEST)));
    }

    @Test
    public void updateThreeAdsWithDifferentOperations() {
        Long adIdForAdd = api.userSteps.adsSteps().addDefaultTextAd(adGroupId);
        Long adIdForRemove = api.userSteps.adsSteps().addAd(new AdAddItemMap()
                .withAdGroupId(adGroupId)
                .withTextAd(new TextAdAddMap()
                        .defaultTextAd()
                        .withAdExtensionIds(adExtensionId)));
        Long adIdForSet = api.userSteps.adsSteps().addAd(new AdAddItemMap()
                .withAdGroupId(adGroupId)
                .withTextAd(new TextAdAddMap()
                        .defaultTextAd()
                        .withAdExtensionIds(adExtensionId)));
        api.userSteps.adsSteps().shouldGetResultOnUpdate(new UpdateRequestMap()
                        .withAds(new AdUpdateItemMap()
                                        .withId(adIdForAdd)
                                        .withTextAd(new TextAdUpdateMap()
                                                .defaultAd()
                                                .withCalloutSetting(new AdExtensionSettingMap()
                                                        .withAdExtensions(new AdExtensionSettingItemMap()
                                                                .withAdExtensionId(adExtensionId)
                                                                .withOperation(OperationEnum.ADD)))),
                                new AdUpdateItemMap()
                                        .withId(adIdForRemove)
                                        .withTextAd(new TextAdUpdateMap()
                                                .defaultAd()
                                                .withCalloutSetting(new AdExtensionSettingMap()
                                                        .withAdExtensions(new AdExtensionSettingItemMap()
                                                                .withAdExtensionId(adExtensionId)
                                                                .withOperation(OperationEnum.REMOVE)))),
                                new AdUpdateItemMap()
                                        .withId(adIdForSet)
                                        .withTextAd(new TextAdUpdateMap()
                                                .defaultAd()
                                                .withCalloutSetting(new AdExtensionSettingMap()
                                                        .withAdExtensions(new AdExtensionSettingItemMap()
                                                                .withAdExtensionId(adExtensionIdElse)
                                                                .withOperation(OperationEnum.SET))))),
                ExpectedResult.success(adIdForAdd),
                ExpectedResult.success(adIdForRemove),
                ExpectedResult.success(adIdForSet));

        List<BannersAdditionsRecord> bannersAdditions =
                jooqDbSteps.bannerAdditionsSteps().getBannersAdditionsRecordsByBids(new Long[]{adIdForAdd, adIdForRemove, adIdForSet});
        BannersAdditionsRecord expectedBannersAdditions =
                new BannersAdditionsRecord(adIdForAdd, adExtensionId, BannersAdditionsAdditionsType.callout, (short) 1);
        BannersAdditionsRecord expectedBannersAdditionsElse =
                new BannersAdditionsRecord(adIdForSet, adExtensionIdElse, BannersAdditionsAdditionsType.callout, (short) 1);

        assertThat("дополнения правильно привязались к объявлению",
                bannersAdditions, recordsDiffer(Arrays.asList(expectedBannersAdditions, expectedBannersAdditionsElse)));
    }
}
