package ru.yandex.autotests.direct.api.campaigns.get.cpmbannercampaign;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import com.yandex.direct.api.v5.campaigns.CampaignFieldEnum;
import com.yandex.direct.api.v5.campaigns.CampaignGetItem;
import com.yandex.direct.api.v5.campaigns.CpmBannerCampaignFieldEnum;
import com.yandex.direct.api.v5.campaigns.CpmBannerCampaignNetworkStrategy;
import com.yandex.direct.api.v5.campaigns.CpmBannerCampaignNetworkStrategyTypeEnum;
import com.yandex.direct.api.v5.campaigns.CpmBannerCampaignSearchStrategy;
import com.yandex.direct.api.v5.campaigns.GetResponse;
import com.yandex.direct.api.v5.general.YesNoEnum;
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.utils.tags.TagDictionary;
import ru.yandex.autotests.directapi.apiclient.config.Semaphore;
import ru.yandex.autotests.directapi.model.api5.campaigns.CampaignAddItemMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.CampaignsSelectionCriteriaMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.CpmBannerCampaignAddItemMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.CpmBannerCampaignNetworkStrategyAddMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.CpmBannerCampaignStrategyAddMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.GetRequestMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.StrategyCpDecreasedPriceForRepeatedImpressionsAddMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.StrategyCpMaximumImpressionsAddMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.StrategyWbDecreasedPriceForRepeatedImpressionsAddMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.StrategyWbMaximumImpressionsAddMap;
import ru.yandex.autotests.directapi.rules.ApiSteps;
import ru.yandex.autotests.directapi.rules.Trashman;
import ru.yandex.qatools.Tag;
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 com.yandex.direct.api.v5.campaigns.CpmBannerCampaignNetworkStrategyTypeEnum.CP_DECREASED_PRICE_FOR_REPEATED_IMPRESSIONS;
import static com.yandex.direct.api.v5.campaigns.CpmBannerCampaignNetworkStrategyTypeEnum.CP_MAXIMUM_IMPRESSIONS;
import static com.yandex.direct.api.v5.campaigns.CpmBannerCampaignNetworkStrategyTypeEnum.WB_DECREASED_PRICE_FOR_REPEATED_IMPRESSIONS;
import static com.yandex.direct.api.v5.campaigns.CpmBannerCampaignNetworkStrategyTypeEnum.WB_MAXIMUM_IMPRESSIONS;
import static com.yandex.direct.api.v5.campaigns.CpmBannerCampaignSearchStrategyTypeEnum.SERVING_OFF;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assumeThat;

@Aqua.Test
@Issue("https://st.yandex-team.ru/DIRECT-83722")
@Features(CampaignsFeatures.GET)
@Tag(TagDictionary.TRUNK)
@Description("Проверка возможности получить стратегию в сети в медийной кампании")
public class GetStrategiesTest {

    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final String START_DATE = LocalDateTime.now().format(FORMATTER);
    private static final String END_DATE = LocalDateTime.now().plusDays(2L).format(FORMATTER);
    private static final YesNoEnum AUTO_CONTINUE = YesNoEnum.YES;

    private static final Long BUDGET = 3000000000L;
    private static final Long BUDGET2 = 4000000000L;

    private static String client = CampaignsLogins.GET_CLIENT;

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

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

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

    private static Long campaignId;

    @Test
    public void checkManualCpmNetworkStrategy() {
        campaignId = api.userSteps.campaignSteps().addDefaultCpmBannerCampaign();

        CampaignGetItem campaign = getCampaignItem();

        CpmBannerCampaignNetworkStrategy networkStrategy = campaign.getCpmBannerCampaign().getBiddingStrategy()
                .getNetwork();
        CpmBannerCampaignSearchStrategy searchStrategy = campaign.getCpmBannerCampaign().getBiddingStrategy()
                .getSearch();

        assertThat("Получили нужную стратегию", networkStrategy.getBiddingStrategyType(),
                is(CpmBannerCampaignNetworkStrategyTypeEnum.MANUAL_CPM));
        assertThat("Получили нужную стратегию", searchStrategy.getBiddingStrategyType(),
                is(SERVING_OFF));

        assertThat("Вернулась одна стратегия",
                networkStrategy.getCpDecreasedPriceForRepeatedImpressions(), nullValue());
        assertThat("Вернулась одна стратегия",
                networkStrategy.getWbDecreasedPriceForRepeatedImpressions(), nullValue());
        assertThat("Вернулась одна стратегия",
                networkStrategy.getCpMaximumImpressions(), nullValue());
        assertThat("Вернулась одна стратегия",
                networkStrategy.getWbMaximumImpressions(), nullValue());
    }

    @Test
    public void checkWbDecreasedPriceForRepeatedImpressionsStrategy() {
        campaignId = createCampaignWithNetworkStrategy(
                new CpmBannerCampaignNetworkStrategyAddMap()
                        .withWbDecreasedPriceForRepeatedImpressions(
                                new StrategyWbDecreasedPriceForRepeatedImpressionsAddMap()
                                        .withAverageCpm(BUDGET)
                                        .withSpendLimit(BUDGET2))
                        .withBiddingStrategyType(WB_DECREASED_PRICE_FOR_REPEATED_IMPRESSIONS));

        CampaignGetItem campaign = getCampaignItem();

        CpmBannerCampaignNetworkStrategy networkStrategy = campaign.getCpmBannerCampaign().getBiddingStrategy()
                .getNetwork();
        CpmBannerCampaignSearchStrategy searchStrategy = campaign.getCpmBannerCampaign().getBiddingStrategy()
                .getSearch();

        assertThat("Получили нужную стратегию", networkStrategy.getBiddingStrategyType(),
                is(WB_DECREASED_PRICE_FOR_REPEATED_IMPRESSIONS));
        assertThat("Получили нужную стратегию", searchStrategy.getBiddingStrategyType(),
                is(SERVING_OFF));

        assertThat("Вернулась одна стратегия",
                networkStrategy.getCpDecreasedPriceForRepeatedImpressions(), nullValue());
        assertThat("Вернулась одна стратегия",
                networkStrategy.getWbDecreasedPriceForRepeatedImpressions(), notNullValue());
        assertThat("Вернулась одна стратегия",
                networkStrategy.getCpMaximumImpressions(), nullValue());
        assertThat("Вернулась одна стратегия",
                networkStrategy.getWbMaximumImpressions(), nullValue());

        assertThat("Поле AverageCpm установлено правильно",
                networkStrategy.getWbDecreasedPriceForRepeatedImpressions().getAverageCpm(), is(BUDGET));
        assertThat("Поле SpendLimit установлено правильно",
                networkStrategy.getWbDecreasedPriceForRepeatedImpressions().getSpendLimit(), is(BUDGET2));
    }

    @Test
    public void checkCpDecreasedPriceForRepeatedImpressionsStrategy() {
        campaignId = createCampaignWithNetworkStrategy(
                new CpmBannerCampaignNetworkStrategyAddMap()
                        .withCpDecreasedPriceForRepeatedImpressions(
                                new StrategyCpDecreasedPriceForRepeatedImpressionsAddMap()
                                        .withAverageCpm(BUDGET)
                                        .withSpendLimit(BUDGET2)
                                        .withStartDate(START_DATE)
                                        .withEndDate(END_DATE)
                                        .withAutoContinue(AUTO_CONTINUE))
                        .withBiddingStrategyType(CP_DECREASED_PRICE_FOR_REPEATED_IMPRESSIONS)
        );

        CampaignGetItem campaign = getCampaignItem();

        CpmBannerCampaignNetworkStrategy networkStrategy = campaign.getCpmBannerCampaign().getBiddingStrategy()
                .getNetwork();
        CpmBannerCampaignSearchStrategy searchStrategy = campaign.getCpmBannerCampaign().getBiddingStrategy()
                .getSearch();

        assertThat("Получили нужную стратегию", networkStrategy.getBiddingStrategyType(),
                is(CP_DECREASED_PRICE_FOR_REPEATED_IMPRESSIONS));
        assertThat("Получили нужную стратегию", searchStrategy.getBiddingStrategyType(),
                is(SERVING_OFF));

        assertThat("Вернулась одна стратегия",
                networkStrategy.getCpDecreasedPriceForRepeatedImpressions(), notNullValue());
        assertThat("Вернулась одна стратегия",
                networkStrategy.getWbDecreasedPriceForRepeatedImpressions(), nullValue());
        assertThat("Вернулась одна стратегия",
                networkStrategy.getCpMaximumImpressions(), nullValue());
        assertThat("Вернулась одна стратегия",
                networkStrategy.getWbMaximumImpressions(), nullValue());

        assertThat("Поле StartDate установлено правильно",
                networkStrategy.getCpDecreasedPriceForRepeatedImpressions().getStartDate(), is(START_DATE));
        assertThat("Поле EndDate установлено правильно",
                networkStrategy.getCpDecreasedPriceForRepeatedImpressions().getEndDate(), is(END_DATE));
        assertThat("Поле AutoContinue установлено правильно",
                networkStrategy.getCpDecreasedPriceForRepeatedImpressions().getAutoContinue(), is(AUTO_CONTINUE));
        assertThat("Поле AverageCpm установлено правильно",
                networkStrategy.getCpDecreasedPriceForRepeatedImpressions().getAverageCpm(), is(BUDGET));
        assertThat("Поле SpendLimit установлено правильно",
                networkStrategy.getCpDecreasedPriceForRepeatedImpressions().getSpendLimit(), is(BUDGET2));
    }

    @Test
    public void checkWbMaximumImpressionsStrategy() {
        campaignId = createCampaignWithNetworkStrategy(
                new CpmBannerCampaignNetworkStrategyAddMap()
                        .withWbMaximumImpressions(
                                new StrategyWbMaximumImpressionsAddMap()
                                        .withAverageCpm(BUDGET)
                                        .withSpendLimit(BUDGET2))
                        .withBiddingStrategyType(WB_MAXIMUM_IMPRESSIONS));

        CampaignGetItem campaign = getCampaignItem();

        CpmBannerCampaignNetworkStrategy networkStrategy = campaign.getCpmBannerCampaign().getBiddingStrategy()
                .getNetwork();
        CpmBannerCampaignSearchStrategy searchStrategy = campaign.getCpmBannerCampaign().getBiddingStrategy()
                .getSearch();

        assertThat("Получили нужную стратегию", networkStrategy.getBiddingStrategyType(),
                is(WB_MAXIMUM_IMPRESSIONS));
        assertThat("Получили нужную стратегию", searchStrategy.getBiddingStrategyType(),
                is(SERVING_OFF));

        assertThat("Вернулась одна стратегия",
                networkStrategy.getCpDecreasedPriceForRepeatedImpressions(), nullValue());
        assertThat("Вернулась одна стратегия",
                networkStrategy.getWbDecreasedPriceForRepeatedImpressions(), nullValue());
        assertThat("Вернулась одна стратегия",
                networkStrategy.getCpMaximumImpressions(), nullValue());
        assertThat("Вернулась одна стратегия",
                networkStrategy.getWbMaximumImpressions(), notNullValue());

        assertThat("Поле AverageCpm установлено правильно",
                networkStrategy.getWbMaximumImpressions().getAverageCpm(), is(BUDGET));
        assertThat("Поле SpendLimit установлено правильно",
                networkStrategy.getWbMaximumImpressions().getSpendLimit(), is(BUDGET2));
    }

    @Test
    public void checkCpMaximumImpressionsStrategy() {
        campaignId = createCampaignWithNetworkStrategy(
                new CpmBannerCampaignNetworkStrategyAddMap()
                        .withCpMaximumImpressions(
                                new StrategyCpMaximumImpressionsAddMap()
                                        .withAverageCpm(BUDGET)
                                        .withSpendLimit(BUDGET2)
                                        .withStartDate(START_DATE)
                                        .withEndDate(END_DATE)
                                        .withAutoContinue(AUTO_CONTINUE))
                        .withBiddingStrategyType(CP_MAXIMUM_IMPRESSIONS));

        CampaignGetItem campaign = getCampaignItem();

        CpmBannerCampaignNetworkStrategy networkStrategy = campaign.getCpmBannerCampaign().getBiddingStrategy()
                .getNetwork();
        CpmBannerCampaignSearchStrategy searchStrategy = campaign.getCpmBannerCampaign().getBiddingStrategy()
                .getSearch();

        assertThat("Получили нужную стратегию", networkStrategy.getBiddingStrategyType(),
                is(CP_MAXIMUM_IMPRESSIONS));
        assertThat("Получили нужную стратегию", searchStrategy.getBiddingStrategyType(),
                is(SERVING_OFF));

        assertThat("Вернулась одна стратегия",
                networkStrategy.getCpDecreasedPriceForRepeatedImpressions(), nullValue());
        assertThat("Вернулась одна стратегия",
                networkStrategy.getWbDecreasedPriceForRepeatedImpressions(), nullValue());
        assertThat("Вернулась одна стратегия",
                networkStrategy.getCpMaximumImpressions(), notNullValue());
        assertThat("Вернулась одна стратегия",
                networkStrategy.getWbMaximumImpressions(), nullValue());

        assertThat("Поле StartDate установлено правильно",
                networkStrategy.getCpMaximumImpressions().getStartDate(), is(START_DATE));
        assertThat("Поле EndDate установлено правильно",
                networkStrategy.getCpMaximumImpressions().getEndDate(), is(END_DATE));
        assertThat("Поле AutoContinue установлено правильно",
                networkStrategy.getCpMaximumImpressions().getAutoContinue(), is(AUTO_CONTINUE));
        assertThat("Поле AverageCpm установлено правильно",
                networkStrategy.getCpMaximumImpressions().getAverageCpm(), is(BUDGET));
        assertThat("Поле SpendLimit установлено правильно",
                networkStrategy.getCpMaximumImpressions().getSpendLimit(), is(BUDGET2));
    }

    private Long createCampaignWithNetworkStrategy(CpmBannerCampaignNetworkStrategyAddMap strategyMap) {
        return api.userSteps.campaignSteps().addCampaign(
                new CampaignAddItemMap()
                        .defaultCampaignAddItem()
                        .withCpmBannerCampaign(new CpmBannerCampaignAddItemMap()
                                .defaultCpmBannerCampaign()
                                .withBiddingStrategy(new CpmBannerCampaignStrategyAddMap()
                                        .defaultCpmBannerCampaignStrategy()
                                        .withNetwork(strategyMap))));
    }

    private CampaignGetItem getCampaignItem() {
        GetResponse getResponse = api.as(client).userSteps.campaignSteps().campaignsGet(
                new GetRequestMap().withSelectionCriteria(
                        new CampaignsSelectionCriteriaMap()
                                .withIds(campaignId))
                        .withFieldNames(CampaignFieldEnum.ID)
                        .withCpmBannerCampaignFieldNames(CpmBannerCampaignFieldEnum.BIDDING_STRATEGY));

        assumeThat("Вернулась одна кампания", getResponse.getCampaigns(), hasSize(1));

        return getResponse.getCampaigns().get(0);
    }
}
