package ru.yandex.autotests.directintapi.bstransport.main.banner.parameters.bannerprices;

import java.math.BigDecimal;

import javax.annotation.Nonnull;

import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;

import ru.yandex.aqua.annotations.project.Aqua;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.BannerPricesCurrency;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.BannerPricesPrefix;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.BannerPricesRecord;
import ru.yandex.autotests.direct.db.steps.DirectJooqDbSteps;
import ru.yandex.autotests.direct.utils.config.DirectTestRunProperties;
import ru.yandex.autotests.direct.utils.tags.TagDictionary;
import ru.yandex.autotests.directapi.darkside.Logins;
import ru.yandex.autotests.directapi.darkside.connection.Semaphore;
import ru.yandex.autotests.directapi.darkside.model.RunBsTransportScriptResponse;
import ru.yandex.autotests.directapi.darkside.model.bslogs.clientdata.Banner;
import ru.yandex.autotests.directapi.darkside.model.bslogs.clientdata.Campaign;
import ru.yandex.autotests.directapi.darkside.model.bslogs.clientdata.Context;
import ru.yandex.autotests.directapi.model.api5.ads.AdAddItemMap;
import ru.yandex.autotests.directapi.model.api5.ads.TextAdAddMap;
import ru.yandex.autotests.directapi.rules.ApiSteps;
import ru.yandex.autotests.directapi.rules.Trashman;
import ru.yandex.autotests.directintapi.bstransport.FeatureNames;
import ru.yandex.autotests.directintapi.bstransport.StoriesNames;
import ru.yandex.qatools.Tag;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Issue;
import ru.yandex.qatools.allure.annotations.Stories;
import ru.yandex.qatools.allure.annotations.Title;
import ru.yandex.qatools.hazelcast.SemaphoreRule;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;

@Aqua.Test
@Tag(TagDictionary.RELEASE)
@Issue("https://st.yandex-team.ru/DIRECT-89163")
@Title("Транспорт: проверка отправки в БК цен на товар на баннере")
@Stories(StoriesNames.BANNER_PARAMS_PRICES)
@Features({FeatureNames.BANNERS})
public class BsTransportBannerPricesTest {

    private static final String LOGIN = Logins.LOGIN_TRANSPORT;
    private static final String PPC_PROPERTY_NAME = "BANNER_PRICE_TO_BS_ENABLED";
    public static final String TEXT_IN_RUSSIAN = "текст на русском";
    public static final String PREFIX_NONE = "0";
    public static final String PREFIX_FROM = "1";
    public static final String PREFIX_TO = "2";

    private static int shard;

    @ClassRule
    public static ApiSteps api = new ApiSteps().as(LOGIN);
    @ClassRule
    public static SemaphoreRule semaphore = Semaphore.getSemaphore();
    @Rule
    public Trashman trasher = new Trashman(api);

    private static DirectJooqDbSteps dbSteps;
    private static long campaignId;
    private static long adGroupId;

    private BannerPricesRecord bannerPricesRecord;
    private long bannerId;

    @BeforeClass
    public static void init() {
        shard = api.userSteps.clientFakeSteps().getUserShard(LOGIN);
        dbSteps = new DirectJooqDbSteps().useShard(shard);

        campaignId = api.userSteps.campaignSteps().addDefaultTextCampaign();
        api.userSteps.campaignFakeSteps().makeNewCampaignReadyForSendingToBS(campaignId);
    }

    @Before
    public void setUp() {
        dbSteps.ppcPropertiesSteps().updatePropertyValue(PPC_PROPERTY_NAME, "1");

        adGroupId = api.userSteps.adGroupsSteps().addDefaultGroup(campaignId);
        bannerId = api.userSteps.adsSteps().addAd(new AdAddItemMap()
                .withTextAd(new TextAdAddMap().defaultTextAd().withText(TEXT_IN_RUSSIAN))
                .withAdGroupId(adGroupId), null);
        Long keywordId = api.userSteps.keywordsSteps().addRandomKeyword(adGroupId);

        api.userSteps.bannersFakeSteps().makeBannerFullyModerated(bannerId);
        api.userSteps.groupFakeSteps().makeGroupFullyModerated(adGroupId);
        api.userSteps.phrasesFakeSteps().makeKeywordModerated(keywordId);

        bannerPricesRecord = new BannerPricesRecord()
                .setBid(bannerId)
                .setPrice(BigDecimal.ONE)
                .setPriceOld(BigDecimal.TEN)
                .setPrefix(BannerPricesPrefix.from)
                .setCurrency(BannerPricesCurrency.RUB);
    }

    @Nonnull
    private static Banner sendCampaignToBsAndGetBanner(Long campaignId, Long adGroupId, Long bannerId) {
        Context context = sendCampaignToBs(campaignId, adGroupId);
        return context.getBanner(bannerId);
    }

    private static Context sendCampaignToBs(Long campaignId, Long adGroupId) {
        RunBsTransportScriptResponse resp = api.userSteps.getDarkSideSteps().getTransportSteps()
                .sendNewCampaign(shard, campaignId);
        Campaign campaign = api.userSteps.getDarkSideSteps().getTransportSteps()
                .getClientDataRequestCampaign(resp, 0, campaignId);
        return campaign.getContext(adGroupId);
    }

    @Test
    @Ignore("Для ручного запуска")
    @Title("Отправка отключена в ppc_properties - цены не отправлены в БК")
    public void ppcPropertyDisabledTest() {
        dbSteps.ppcPropertiesSteps().updatePropertyValue(PPC_PROPERTY_NAME, "0");
        dbSteps.bannerPricesSteps().addDefaultBannerPrice(bannerId);
        Banner banner = sendCampaignToBsAndGetBanner(campaignId, adGroupId, bannerId);
        assertThat("цены ушли в БК", banner.getBannerPrice(), nullValue());
    }

    @Test
    @Title("Заполненная цена в баннере - отправлено в БК")
    public void bannerPriceWithAllFieldsSetTest() {
        dbSteps.bannerPricesSteps().addBannerPrice(bannerId, bannerPricesRecord);
        Banner banner = sendCampaignToBsAndGetBanner(campaignId, adGroupId, bannerId);

        validateBanner(banner, is(PREFIX_FROM), bannerId, bannerPricesRecord.getCurrency());
    }

    @Test
    @Title("Заполненная цена в баннере - отправлено в БК")
    public void twoBannersTest() {
        Long secondBannerId = api.userSteps.adsSteps().addAd(new AdAddItemMap()
                .withTextAd(new TextAdAddMap().defaultTextAd().withText(TEXT_IN_RUSSIAN))
                .withAdGroupId(adGroupId), null);
        api.userSteps.bannersFakeSteps().makeBannerFullyModerated(secondBannerId);
        BannerPricesRecord secondPriceRecord = new BannerPricesRecord()
                .setBid(secondBannerId)
                .setPrice(new BigDecimal(2))
                .setPriceOld(new BigDecimal(20))
                .setPrefix(BannerPricesPrefix.to)
                .setCurrency(BannerPricesCurrency.EUR);

        dbSteps.bannerPricesSteps().addBannerPrice(bannerId, bannerPricesRecord);
        dbSteps.bannerPricesSteps().addBannerPrice(secondBannerId, secondPriceRecord);

        Context context = sendCampaignToBs(campaignId, adGroupId);
        validateBanner(context.getBanner(bannerId), is(PREFIX_FROM), bannerId, bannerPricesRecord.getCurrency());
        validateBanner(context.getBanner(secondBannerId), is(PREFIX_TO), secondBannerId, secondPriceRecord.getCurrency());
    }

    @Test
    @Title("Цена без префикса - отправлено в БК")
    public void bannerPriceWithEmptyPrefixTest() {
        dbSteps.bannerPricesSteps().addBannerPrice(bannerId, bannerPricesRecord.setPrefix(null));
        Banner banner = sendCampaignToBsAndGetBanner(campaignId, adGroupId, bannerId);

        validateBanner(banner, is(PREFIX_NONE), bannerId, bannerPricesRecord.getCurrency());
    }

    @Test
    @Title("Цена без старой цены - отправлено в БК")
    public void bannerPriceWithEmptyOldPriceTest() {
        dbSteps.bannerPricesSteps().addBannerPrice(bannerId, bannerPricesRecord.setPriceOld(null));
        Banner banner = sendCampaignToBsAndGetBanner(campaignId, adGroupId, bannerId);

        BannerPricesRecord record = dbSteps.bannerPricesSteps().getBannerPrices(bannerId);
        assertThat("отправленная в БК цена товара на баннере не соответствует ожидаемой",
                banner.getBannerPrice().getPrice(), equalTo(record.getPrice()));
        assertThat("в БК отправлена старая цена", banner.getBannerPrice().getOldPrice(), nullValue());
        assertThat("в БК должна быть отправлена корректная валюта", banner.getBannerPrice().getCurrency(),
                equalTo(bannerPricesRecord.getCurrency()));
        assertThat("в БК отправлен корректный префикс", banner.getBannerPrice().getPrefix(), is(PREFIX_FROM));
    }

    @Test
    @Title("Цена не отправляется для не-ТГО")
    public void bannerPriceNotSentForNonTextAdTest() {
        adGroupId = api.userSteps.adGroupsSteps().addDefaultGroup(campaignId);
        String adImageHash = api.userSteps.imagesStepsV5().addImageAdAdImage(1);
        bannerId = api.userSteps.adsSteps().addDefaultTextImageAd(adGroupId, adImageHash);
        Long keywordId = api.userSteps.keywordsSteps().addRandomKeyword(adGroupId);

        api.userSteps.bannersFakeSteps().makeBannerFullyModerated(bannerId);
        api.userSteps.groupFakeSteps().makeGroupFullyModerated(adGroupId);
        api.userSteps.phrasesFakeSteps().makeKeywordModerated(keywordId);

        dbSteps.bannerPricesSteps().addDefaultBannerPrice(bannerId);
        Banner banner = sendCampaignToBsAndGetBanner(campaignId, adGroupId, bannerId);
        assertThat("цены ушли в БК", banner.getBannerPrice(), nullValue());
    }

    private void validateBanner(Banner banner, Matcher<String> prefixMatcher, long bannerId, BannerPricesCurrency currency) {
        BannerPricesRecord record = dbSteps.bannerPricesSteps().getBannerPrices(bannerId);
        assertThat("отправленная в БК цена товара на баннере не соответствует ожидаемой",
                banner.getBannerPrice().getPrice(), equalTo(record.getPrice()));
        assertThat("отправленная в БК старая цена товара на баннере не соответствует ожидаемой",
                banner.getBannerPrice().getOldPrice(), equalTo(record.getPriceOld()));
        assertThat("в БК должна быть отправлена корректная валюта", banner.getBannerPrice().getCurrency(),
                equalTo(currency));
        assertThat("в БК должен быть отправлен корректный префикс", banner.getBannerPrice().getPrefix(), prefixMatcher);
    }
}
