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

import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.util.streamex.StreamEx;

import com.yandex.direct.api.v5.campaigns.CampaignFieldEnum;
import com.yandex.direct.api.v5.campaigns.CpmBannerCampaignFieldEnum;
import com.yandex.direct.api.v5.campaigns.CpmBannerCampaignSettingGet;
import com.yandex.direct.api.v5.campaigns.CpmBannerCampaignSettingsEnum;
import com.yandex.direct.api.v5.campaigns.CpmBannerCampaignSettingsGetEnum;
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.apiclient.errors.Api5ErrorDetails;
import ru.yandex.autotests.directapi.model.api5.campaigns.AddRequestMap;
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.CpmBannerCampaignSettingGetMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.CpmBannerCampaignSettingMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.GetRequestMap;
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.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 org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.notNullValue;
import static ru.yandex.autotests.directapi.matchers.beans.version5.BeanDifferMatcherV5.beanDifferV5;
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)
@Description("Проверка поля Settings для медийной кампании")
@Tag(TagDictionary.TRUNK)
public class GetSettingsTest {

    private static final String client = CampaignsLogins.CLIENT;

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

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

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

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

        Map<CpmBannerCampaignSettingsGetEnum, YesNoEnum> expectedSettings = new HashMap<>();
        expectedSettings.put(CpmBannerCampaignSettingsGetEnum.ADD_METRICA_TAG, YesNoEnum.YES);
        expectedSettings.put(CpmBannerCampaignSettingsGetEnum.ADD_OPENSTAT_TAG, YesNoEnum.NO);
        expectedSettings.put(CpmBannerCampaignSettingsGetEnum.ADD_TO_FAVORITES, YesNoEnum.NO);
        expectedSettings.put(CpmBannerCampaignSettingsGetEnum.DAILY_BUDGET_ALLOWED, YesNoEnum.YES);
        expectedSettings.put(CpmBannerCampaignSettingsGetEnum.ENABLE_AREA_OF_INTEREST_TARGETING, YesNoEnum.YES);
        expectedSettings.put(CpmBannerCampaignSettingsGetEnum.ENABLE_SITE_MONITORING, YesNoEnum.NO);
        expectedSettings.put(CpmBannerCampaignSettingsGetEnum.REQUIRE_SERVICING, YesNoEnum.NO);
        expectedSettings.put(CpmBannerCampaignSettingsGetEnum.SHARED_ACCOUNT_ENABLED, YesNoEnum.NO);

        Map<CpmBannerCampaignSettingsGetEnum, YesNoEnum> settingsActual = StreamEx.of(getSettings(client))
                .toMap(CpmBannerCampaignSettingGet::getOption, CpmBannerCampaignSettingGet::getValue);

        assertThat("Корректный набор настроек",
                settingsActual, beanDifferV5(expectedSettings));
    }

    @Test
    public void manualCampaignSettingsForNotServicedClientTest() {
        api.userSteps.campaignSteps().shouldGetResultOnAdd(
                new AddRequestMap().withCampaigns(
                        new CampaignAddItemMap().defaultCampaignAddItem()
                                .withCpmBannerCampaign(new CpmBannerCampaignAddItemMap()
                                        .defaultCpmBannerCampaign()
                                        .withSettings(
                                                new CpmBannerCampaignSettingMap()
                                                        .withOption(CpmBannerCampaignSettingsEnum.REQUIRE_SERVICING)
                                                        .withValue(YesNoEnum.YES)))),
                ExpectedResult.warningsIgnoringDetailsAndMessage(new Notification(10163,
                        Api5ErrorDetails.CAMPAIGN_WILL_NOT_BE_SENT_TO_SERVING)));
    }

    @Test
    public void manualCampaignSettingsForServicedClientTest() {
        String servClient = CampaignsLogins.GET_SERV_CLIENT;

        campaignId =
                api.as(servClient).userSteps.campaignSteps().addCampaign(new CampaignAddItemMap().defaultCampaignAddItem()
                        .withCpmBannerCampaign(new CpmBannerCampaignAddItemMap()
                                .defaultCpmBannerCampaign()
                                .withSettings(
                                        new CpmBannerCampaignSettingMap()
                                                .withOption(CpmBannerCampaignSettingsEnum.ADD_TO_FAVORITES)
                                                .withValue(YesNoEnum.YES),
                                        new CpmBannerCampaignSettingMap()
                                                .withOption(CpmBannerCampaignSettingsEnum.REQUIRE_SERVICING)
                                                .withValue(YesNoEnum.YES),
                                        new CpmBannerCampaignSettingMap()
                                                .withOption(CpmBannerCampaignSettingsEnum.ENABLE_SITE_MONITORING)
                                                .withValue(YesNoEnum.YES),
                                        new CpmBannerCampaignSettingMap()
                                                .withOption(CpmBannerCampaignSettingsEnum.ADD_METRICA_TAG)
                                                .withValue(YesNoEnum.YES),
                                        new CpmBannerCampaignSettingMap()
                                                .withOption(CpmBannerCampaignSettingsEnum.ADD_OPENSTAT_TAG)
                                                .withValue(YesNoEnum.YES),
                                        new CpmBannerCampaignSettingMap()
                                                .withOption(CpmBannerCampaignSettingsEnum.ENABLE_AREA_OF_INTEREST_TARGETING)
                                                .withValue(YesNoEnum.NO)
                                )));

        List<Object> expectedSettings = Arrays.asList(
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.ADD_METRICA_TAG)
                        .withValue(YesNoEnum.YES).getBean(),
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.ADD_OPENSTAT_TAG)
                        .withValue(YesNoEnum.YES).getBean(),
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.ADD_TO_FAVORITES)
                        .withValue(YesNoEnum.YES).getBean(),
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.DAILY_BUDGET_ALLOWED)
                        .withValue(YesNoEnum.YES).getBean(),
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.ENABLE_AREA_OF_INTEREST_TARGETING)
                        .withValue(YesNoEnum.NO).getBean(),
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.ENABLE_SITE_MONITORING)
                        .withValue(YesNoEnum.YES).getBean(),
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.REQUIRE_SERVICING)
                        .withValue(YesNoEnum.YES).getBean(),
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.SHARED_ACCOUNT_ENABLED)
                        .withValue(YesNoEnum.NO).getBean());

        assertThat("Корректный набор настроек",
                getSettings(servClient), beanDifferV5(expectedSettings));
    }

    @Test
    public void defaultCampaignSettingsForClientWithSharedAccountTest() {
        String accountClient = CampaignsLogins.GET_ACCOUNT_CLIENT;

        campaignId = api.as(accountClient).userSteps.campaignSteps().addDefaultCpmBannerCampaign();

        List<Object> expectedSettings = Arrays.asList(
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.ADD_METRICA_TAG)
                        .withValue(YesNoEnum.YES).getBean(),
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.ADD_OPENSTAT_TAG)
                        .withValue(YesNoEnum.NO).getBean(),
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.ADD_TO_FAVORITES)
                        .withValue(YesNoEnum.NO).getBean(),
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.DAILY_BUDGET_ALLOWED)
                        .withValue(YesNoEnum.YES).getBean(),
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.ENABLE_AREA_OF_INTEREST_TARGETING)
                        .withValue(YesNoEnum.YES).getBean(),
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.ENABLE_SITE_MONITORING)
                        .withValue(YesNoEnum.NO).getBean(),
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.REQUIRE_SERVICING)
                        .withValue(YesNoEnum.NO).getBean(),
                new CpmBannerCampaignSettingGetMap()
                        .withOption(CpmBannerCampaignSettingsGetEnum.SHARED_ACCOUNT_ENABLED)
                        .withValue(YesNoEnum.YES).getBean());

        assertThat("Корректный набор настроек",
                getSettings(accountClient), beanDifferV5(expectedSettings));
    }

    private List<CpmBannerCampaignSettingGet> getSettings(String client) {
        GetResponse getResponse = api.as(client).userSteps.campaignSteps().campaignsGet(
                new GetRequestMap().withSelectionCriteria(
                                new CampaignsSelectionCriteriaMap()
                                        .withIds(campaignId))
                        .withFieldNames(CampaignFieldEnum.ID)
                        .withCpmBannerCampaignFieldNames(CpmBannerCampaignFieldEnum.SETTINGS));
        assumeThat("Получили созданную кампанию", getResponse.getCampaigns(), hasSize(1));

        List<CpmBannerCampaignSettingGet> settings =
                getResponse.getCampaigns().get(0).getCpmBannerCampaign().getSettings();

        assumeThat("Получили настройки кампании", settings, notNullValue());

        // TODO DIRECT-169007: после переключения campaigns.get на java сортировку можно будет убрать
        settings.sort(Comparator.comparing(x -> x.getOption().value()));

        return settings;
    }
}
