package ru.yandex.autotests.direct.api.campaigns.update.textcampaign;

import java.math.BigInteger;

import javax.annotation.ParametersAreNonnullByDefault;

import com.yandex.direct.api.v5.campaigns.CampaignFieldEnum;
import com.yandex.direct.api.v5.campaigns.GetResponse;
import com.yandex.direct.api.v5.campaigns.ObjectFactory;
import com.yandex.direct.api.v5.campaigns.TextCampaignFieldEnum;
import com.yandex.direct.api.v5.campaigns.TextCampaignSettingsEnum;
import com.yandex.direct.api.v5.general.YesNoEnum;
import org.hamcrest.Matchers;
import org.junit.Before;
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.campaigns.CampaignsFeatures;
import ru.yandex.autotests.direct.api.campaigns.CampaignsLogins;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampOptionsBroadMatchFlag;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.CampOptionsRecord;
import ru.yandex.autotests.directapi.apiclient.config.Semaphore;
import ru.yandex.autotests.directapi.apiclient.errors.Api5ErrorDetails;
import ru.yandex.autotests.directapi.model.api5.campaigns.CampaignAddItemMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.CampaignUpdateItemMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.CampaignsSelectionCriteriaMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.GetRequestMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.RelevantKeywordsSettingMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.TextCampaignAddItemMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.TextCampaignGetItemMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.TextCampaignSearchStrategyMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.TextCampaignSettingMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.TextCampaignStrategyAddMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.TextCampaignStrategyMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.TextCampaignUpdateItemMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.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.junit.Assume.assumeThat;
import static org.junit.Assume.assumeTrue;
import static ru.yandex.autotests.directapi.matchers.beandiffer2.BeanDifferMatcherV5.beanDifferV5;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;

@Aqua.Test
@Features(CampaignsFeatures.UPDATE)
@Description("Проверка включения ДРФ по умолчанию при обновлении")
@Issue("https://st.yandex-team.ru/DIRECT-68257")
@ParametersAreNonnullByDefault
public class RelevantKeywordsEnableByDefault {
    private static final String CLIENT = CampaignsLogins.CLIENT;
    private static final Integer CUSTOM_BUDGET_PERCENT = 75;
    private static final Integer DEFAULT_BUDGET_PERCENT = 40;

    @ClassRule
    public static ApiSteps api = new ApiSteps().version(5).as(CLIENT);

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

    private static CampOptionsRecord campOptionsRelevantKeywordsDisabled;
    private static int shard;

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

    public Long campaignId;

    @BeforeClass
    public static void prepareCommon() {
        api.userSteps.clientFakeSteps().fakeClearClientSpentUnits(CLIENT);
        shard = api.userSteps.clientFakeSteps().getUserShard(CLIENT);
        campOptionsRelevantKeywordsDisabled = new CampOptionsRecord();
        campOptionsRelevantKeywordsDisabled.setBroadMatchFlag(CampOptionsBroadMatchFlag.No);
        campOptionsRelevantKeywordsDisabled.setBroadMatchLimit(0);
        campOptionsRelevantKeywordsDisabled.setBroadMatchGoalId(BigInteger.ZERO);
    }

    @Before
    public void prepare() {
        campaignId = api.userSteps.campaignSteps().addCampaign(
                new CampaignAddItemMap()
                        .defaultCampaignAddItem()
                        .withTextCampaign(new TextCampaignAddItemMap()
                                .withBiddingStrategy(
                                        new TextCampaignStrategyAddMap().defaultTextCampaignStrategy())));

        CampOptionsRecord campOptions = api.userSteps.getDirectJooqDbSteps().useShard(shard).campaignsSteps().getCampOptionsById(campaignId);

        matchCampOptionsDrfSettings(campOptions, campOptionsRelevantKeywordsDisabled);
    }

    @Test
    @Description("При обновлении кампании с выключенным ДФР и при указании блока RelevantKeywords ДРФ дожен включиться")
    public void updateWithRelevantKeywordsTest() {
        api.userSteps.campaignSteps().shouldGetResultOnUpdate(
                new UpdateRequestMap()
                        .withCampaigns(new CampaignUpdateItemMap()
                                .withId(campaignId)
                                .withTextCampaign(new TextCampaignUpdateItemMap()
                                        .withRelevantKeywords(new RelevantKeywordsSettingMap()
                                                .withBudgetPercent(CUSTOM_BUDGET_PERCENT)
                                                .withOptimizeGoalId(null)))),
                ExpectedResult.success()
        );

        CampOptionsRecord campOptionsRelevantKeywordsEnabled = new CampOptionsRecord();
        campOptionsRelevantKeywordsEnabled.setBroadMatchFlag(CampOptionsBroadMatchFlag.Yes);
        campOptionsRelevantKeywordsEnabled.setBroadMatchLimit(CUSTOM_BUDGET_PERCENT);
        campOptionsRelevantKeywordsEnabled.setBroadMatchGoalId(null);

        CampOptionsRecord campOptions = api.userSteps.getDirectJooqDbSteps().useShard(shard).campaignsSteps()
                .getCampOptionsById(campaignId);

        assumeTrue("корректные настройки ДРФ",
                matchCampOptionsDrfSettings(campOptions, campOptionsRelevantKeywordsEnabled));

        GetResponse getResponse = api.userSteps.campaignSteps().campaignsGet(
                new GetRequestMap()
                        .withSelectionCriteria(
                                new CampaignsSelectionCriteriaMap()
                                        .withIds(campaignId)
                        )
                        .withFieldNames(CampaignFieldEnum.ID)
                        .withTextCampaignFieldNames(TextCampaignFieldEnum.RELEVANT_KEYWORDS)
        );

        assertThat("вернулась ожидаемая структура RelevantKeyword",
                getResponse.getCampaigns().get(0).getTextCampaign(),
                beanDifferV5(new TextCampaignGetItemMap().withRelevantKeywords(
                        new RelevantKeywordsSettingMap()
                                .withBudgetPercent(CUSTOM_BUDGET_PERCENT)
                                .withOptimizeGoalId(null)).getBean()));
    }

    @Test
    @Description("При обновлении кампании с выключенным ДФР и при указании настройки ENABLE_RELATED_KEYWORDS = YES ДРФ дожен включиться")
    public void updateWithoutRelevantKeywordsAndWithEnableRelatedKeywordsSettingTest() {
        api.userSteps.campaignSteps().shouldGetResultOnUpdate(
                new UpdateRequestMap()
                        .withCampaigns(new CampaignUpdateItemMap()
                                .withId(campaignId)
                                .withTextCampaign(new TextCampaignUpdateItemMap()
                                        .withSettings(new TextCampaignSettingMap()
                                                .withOption(TextCampaignSettingsEnum.ENABLE_RELATED_KEYWORDS)
                                                .withValue(YesNoEnum.YES)))),
                ExpectedResult.warnings(
                        new Notification(10163, Api5ErrorDetails.CAMPAIGN_SETTING_DEPRECATED,
                                TextCampaignSettingsEnum.ENABLE_RELATED_KEYWORDS))
        );

        CampOptionsRecord campOptionsRelevantKeywordsEnabled = new CampOptionsRecord();
        campOptionsRelevantKeywordsEnabled.setBroadMatchFlag(CampOptionsBroadMatchFlag.Yes);
        campOptionsRelevantKeywordsEnabled.setBroadMatchLimit(DEFAULT_BUDGET_PERCENT);
        campOptionsRelevantKeywordsEnabled.setBroadMatchGoalId(null);

        final CampOptionsRecord campOptions =
                api.userSteps.getDirectJooqDbSteps().useShard(shard).campaignsSteps().getCampOptionsById(campaignId);

        assumeTrue("корректные настройки ДРФ",
                matchCampOptionsDrfSettings(campOptions, campOptionsRelevantKeywordsEnabled));

        GetResponse getResponse = api.userSteps.campaignSteps().campaignsGet(
                new GetRequestMap()
                        .withSelectionCriteria(
                                new CampaignsSelectionCriteriaMap()
                                        .withIds(campaignId)
                        )
                        .withFieldNames(CampaignFieldEnum.ID)
                        .withTextCampaignFieldNames(TextCampaignFieldEnum.RELEVANT_KEYWORDS)
        );

        assertThat("вернулась ожидаемая структура RelevantKeyword",
                getResponse.getCampaigns().get(0).getTextCampaign(),
                beanDifferV5(new TextCampaignGetItemMap().withRelevantKeywords(
                        new RelevantKeywordsSettingMap()
                                .withBudgetPercent(DEFAULT_BUDGET_PERCENT)
                                .withOptimizeGoalId(null)).getBean()));
    }

    @Test
    @Description("При обновлении кампании с выключенным ДФР без указания блока RelevantKeywords и настройки ENABLE_RELATED_KEYWORDS = YES ДРФ не дожен включиться")
    public void updateWithoutRelevantKeywordsAndWithoutEnableRelatedKeywordsSettingTest() {
        api.userSteps.campaignSteps().shouldGetResultOnUpdate(
                new UpdateRequestMap()
                        .withCampaigns(new CampaignUpdateItemMap()
                                .withId(campaignId)
                                .withTextCampaign(new TextCampaignUpdateItemMap()
                                        .withBiddingStrategy(new TextCampaignStrategyMap()
                                                .withSearch(new TextCampaignSearchStrategyMap()
                                                        .defaultHighestPosition())))),
                // конктетная стратегия не важна - важно само обновление без указания настроек
                ExpectedResult.success()
        );

        CampOptionsRecord campOptions = api.userSteps.getDirectJooqDbSteps().useShard(shard).campaignsSteps().getCampOptionsById(campaignId);

        assumeTrue("корректные настройки ДРФ",
                matchCampOptionsDrfSettings(campOptions, campOptionsRelevantKeywordsDisabled));

        GetResponse getResponse = api.userSteps.campaignSteps().campaignsGet(
                new GetRequestMap()
                        .withSelectionCriteria(
                                new CampaignsSelectionCriteriaMap()
                                        .withIds(campaignId)
                        )
                        .withFieldNames(CampaignFieldEnum.ID)
                        .withTextCampaignFieldNames(TextCampaignFieldEnum.RELEVANT_KEYWORDS)
        );

        assertThat("вернулась ожидаемая структура RelevantKeyword",
                getResponse.getCampaigns().get(0).getTextCampaign().getRelevantKeywords(),
                beanDifferV5(new ObjectFactory().createTextCampaignBaseRelevantKeywords(null)));
    }

    @Test
    @Description("При обновлении кампании с выключенным ДФР c указанием блока RelevantKeywords равного null и настройки ENABLE_RELATED_KEYWORDS = YES ДРФ не дожен включиться")
    public void updateWithRelevantKeywordsEqualToNullAndWithEnableRelatedKeywordsSettingTest() {
        api.userSteps.campaignSteps().shouldGetResultOnUpdate(
                new UpdateRequestMap()
                        .withCampaigns(new CampaignUpdateItemMap()
                                .withId(campaignId)
                                .withTextCampaign(new TextCampaignUpdateItemMap()
                                        .withBiddingStrategy(new TextCampaignStrategyMap()
                                                .withSearch(new TextCampaignSearchStrategyMap()
                                                        .defaultHighestPosition()))
                                        .withRelevantKeywords(null)
                                        .withSettings(new TextCampaignSettingMap()
                                                .withOption(TextCampaignSettingsEnum.ENABLE_RELATED_KEYWORDS)
                                                .withValue(YesNoEnum.YES)))),
                ExpectedResult.warnings(
                        new Notification(10163, Api5ErrorDetails.CAMPAIGN_SETTING_DEPRECATED,
                                TextCampaignSettingsEnum.ENABLE_RELATED_KEYWORDS))
        );

        CampOptionsRecord campOptions = api.userSteps.getDirectJooqDbSteps().useShard(shard).campaignsSteps()
                .getCampOptionsById(campaignId);

        assumeTrue("корректные настройки ДРФ",
                matchCampOptionsDrfSettings(campOptions, campOptionsRelevantKeywordsDisabled));

        GetResponse getResponse = api.userSteps.campaignSteps().campaignsGet(
                new GetRequestMap()
                        .withSelectionCriteria(
                                new CampaignsSelectionCriteriaMap()
                                        .withIds(campaignId))
                        .withFieldNames(CampaignFieldEnum.ID)
                        .withTextCampaignFieldNames(TextCampaignFieldEnum.RELEVANT_KEYWORDS)
        );

        assertThat("вернулась ожидаемая структура RelevantKeyword",
                getResponse.getCampaigns().get(0).getTextCampaign().getRelevantKeywords(),
                beanDifferV5(new ObjectFactory().createTextCampaignBaseRelevantKeywords(null)));
    }

    @Test
    @Description("При обновлении кампании с выключенным ДФР c указанием блока RelevantKeywords со значениями, отличными от значений по умоланию, и настройки ENABLE_RELATED_KEYWORDS = YES ДРФ дожен включиться (значения его настроек отличны от значений по умолчанию)")
    public void updateWithNotDefaultRelevantKeywordsAndWithEnableRelatedKeywordsSettingTest() {
        api.userSteps.campaignSteps().shouldGetResultOnUpdate(
                new UpdateRequestMap()
                        .withCampaigns(new CampaignUpdateItemMap()
                                .withId(campaignId)
                                .withTextCampaign(new TextCampaignUpdateItemMap()
                                        .withBiddingStrategy(new TextCampaignStrategyMap()
                                                .withSearch(new TextCampaignSearchStrategyMap()
                                                        .defaultHighestPosition()))
                                        .withRelevantKeywords(new RelevantKeywordsSettingMap()
                                                .withBudgetPercent(CUSTOM_BUDGET_PERCENT)
                                                .withOptimizeGoalId(0L))
                                        .withSettings(new TextCampaignSettingMap()
                                                .withOption(TextCampaignSettingsEnum.ENABLE_RELATED_KEYWORDS)
                                                .withValue(YesNoEnum.YES)))),
                ExpectedResult.warnings(
                        new Notification(10163, Api5ErrorDetails.CAMPAIGN_SETTING_DEPRECATED,
                                TextCampaignSettingsEnum.ENABLE_RELATED_KEYWORDS))
        );

        CampOptionsRecord campOptionsRelevantKeywordsEnabled = new CampOptionsRecord();
        campOptionsRelevantKeywordsEnabled.setBroadMatchFlag(CampOptionsBroadMatchFlag.Yes);
        campOptionsRelevantKeywordsEnabled.setBroadMatchLimit(CUSTOM_BUDGET_PERCENT);
        campOptionsRelevantKeywordsEnabled.setBroadMatchGoalId(BigInteger.ZERO);

        CampOptionsRecord campOptions = api.userSteps.getDirectJooqDbSteps().useShard(shard).campaignsSteps()
                .getCampOptionsById(campaignId);

        assumeTrue("корректные настройки ДРФ",
                matchCampOptionsDrfSettings(campOptions, campOptionsRelevantKeywordsEnabled));
        GetResponse getResponse = api.userSteps.campaignSteps().campaignsGet(
                new GetRequestMap()
                        .withSelectionCriteria(
                                new CampaignsSelectionCriteriaMap()
                                        .withIds(campaignId)
                        )
                        .withFieldNames(CampaignFieldEnum.ID)
                        .withTextCampaignFieldNames(TextCampaignFieldEnum.RELEVANT_KEYWORDS)
        );

        assertThat("вернулась ожидаемая структура RelevantKeyword",
                getResponse.getCampaigns().get(0).getTextCampaign(),
                beanDifferV5(new TextCampaignGetItemMap().withRelevantKeywords(
                        new RelevantKeywordsSettingMap()
                                .withBudgetPercent(CUSTOM_BUDGET_PERCENT)
                                .withOptimizeGoalId(0L)).getBean()));
    }

    private boolean matchCampOptionsDrfSettings(CampOptionsRecord actual, CampOptionsRecord expected) {
        assumeThat("BroadMatchFlag совпадает",
                actual.getBroadMatchFlag(),
                Matchers.equalTo(expected.getBroadMatchFlag()));
        assumeThat("BroadMatchLimit совпадает",
                actual.getBroadMatchLimit(),
                Matchers.equalTo(expected.getBroadMatchLimit()));
        assumeThat("BroadMatchGoalId совпадает",
                actual.getBroadMatchGoalId(),
                Matchers.equalTo(expected.getBroadMatchGoalId()));
        return true;
    }
}
