package ru.yandex.autotests.direct.api.keywordbids.set;

import java.math.BigDecimal;

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.bids.BidsLogins;
import ru.yandex.autotests.direct.api.keywordbids.KeywordBidsFeatures;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.BidsRecord;
import ru.yandex.autotests.direct.utils.money.Currency;
import ru.yandex.autotests.direct.utils.money.Money;
import ru.yandex.autotests.direct.utils.money.MoneyCurrency;
import ru.yandex.autotests.direct.utils.money.MoneyFormat;
import ru.yandex.autotests.directapi.apiclient.config.Semaphore;
import ru.yandex.autotests.directapi.model.api5.keywordbids.KeywordBidExpectedResult;
import ru.yandex.autotests.directapi.model.api5.keywordbids.KeywordBidsSetItemMap;
import ru.yandex.autotests.directapi.model.api5.keywordbids.SetRequestMap;
import ru.yandex.autotests.directapi.rules.ApiSteps;
import ru.yandex.autotests.directapi.rules.Trashman;
import ru.yandex.autotests.irt.testutils.beandiffer2.comparestrategy.defaultcomparestrategy.DefaultCompareStrategies;
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.allure.annotations.Step;
import ru.yandex.qatools.allure.annotations.TestCaseId;
import ru.yandex.qatools.hazelcast.SemaphoreRule;

import static org.hamcrest.Matchers.comparesEqualTo;
import static ru.yandex.autotests.direct.db.utils.JooqRecordDifferMatcher.recordDiffer;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assumeThat;

/**
 * Created by pavryabov on 07.07.16.
 * https://st.yandex-team.ru/TESTIRT-9701
 */
@Aqua.Test
@Features(KeywordBidsFeatures.SET)
@Issue("https://st.yandex-team.ru/DIRECT-55594")
@Description("Обновление ставок у двух разных объектов в одном запросе (объекты из разных кампаний)")
public class SetSeveralObjectsFromDifferentCampaignsTest {

    private static final String CLIENT = BidsLogins.BIDS_CLIENT;

    private static final String KEYWORD = "мониторы";
    private static final String KEYWORD_ELSE = "телевизоры";

    public static final Money PRICE = MoneyCurrency.get(Currency.RUB).getMinPrice().add(1f);
    public static final Money PRICE_ELSE = MoneyCurrency.get(Currency.RUB).getMinPrice().add(2f);
    public static final Money CONTEXT_PRICE = MoneyCurrency.get(Currency.RUB).getMinPrice().add(3f);
    public static final Money CONTEXT_PRICE_ELSE = MoneyCurrency.get(Currency.RUB).getMinPrice().add(4f);

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

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

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

    private Long campaignId1;
    private Long campaignId2;
    private Long adGroupId1;
    private Long adGroupId2;
    private Long keywordId1;
    private Long keywordId2;
    private static int shard;

    @BeforeClass
    public static void getShard() {
        shard = api.userSteps.clientFakeSteps().getUserShard(CLIENT);

    }

    @Before
    @Step("Подготовка данных для теста")
    public void prepareData() {
        api.userSteps.clientFakeSteps().fakeClearClientSpentUnits(BidsLogins.BIDS_CLIENT);
        campaignId1 = api.userSteps.campaignSteps().addDefaultTextCampaign();
        adGroupId1 = api.userSteps.adGroupsSteps().addDefaultGroup(campaignId1);
        Long adId1 = api.userSteps.adsSteps().addDefaultTextAd(adGroupId1);
        keywordId1 = api.userSteps.keywordsSteps().addKeyword(adGroupId1, KEYWORD);
        campaignId2 = api.userSteps.campaignSteps().addDefaultTextCampaign();
        adGroupId2 = api.userSteps.adGroupsSteps().addDefaultGroup(campaignId2);
        Long adId2 = api.userSteps.adsSteps().addDefaultTextAd(adGroupId2);
        keywordId2 = api.userSteps.keywordsSteps().addKeyword(adGroupId2, KEYWORD);
        api.userSteps.bannersFakeSteps().makeBannerActive(adId1, adId2);
        BidsRecord bids = api.userSteps.getDirectJooqDbSteps().useShard(shard).bidsSteps().getBidById(keywordId1);
        BidsRecord expectedBids = new BidsRecord()
                .setCid(campaignId1)
                .setPid(adGroupId1)
                .setId(keywordId1)
                .setPrice(new BigDecimal(
                        MoneyCurrency.get(Currency.RUB).getMinPrice().stringValue(MoneyFormat.TWO_DIGITS_POINT)))
                .setPriceContext(new BigDecimal(
                        MoneyCurrency.get(Currency.RUB).getMinPrice().stringValue(MoneyFormat.TWO_DIGITS_POINT)));
        assumeThat("первая фраза создалась с минимальными ставками", bids,
                recordDiffer(expectedBids).useCompareStrategy(DefaultCompareStrategies.onlyExpectedFields()));
        bids = api.userSteps.getDirectJooqDbSteps().bidsSteps().getBidById(keywordId2);
        expectedBids.setCid(campaignId2);
        expectedBids.setPid(adGroupId2);
        expectedBids.setId(keywordId2);
        assumeThat("вторая фраза создалась с минимальными ставками", bids,
                recordDiffer(expectedBids).useCompareStrategy(DefaultCompareStrategies.onlyExpectedFields()));

    }

    @Test
    @TestCaseId("2915")
    public void setWithTwoDifferentCampaigns() {
        api.userSteps.keywordBidsSteps().shouldGetKeywordBidResultOnSet(
                new SetRequestMap()
                        .withKeywordBids(new KeywordBidsSetItemMap()
                                        .withCampaignId(campaignId1)
                                        .withSearchBid(PRICE.bidLong().longValue())
                                        .withNetworkBid(CONTEXT_PRICE.bidLong().longValue()),
                                new KeywordBidsSetItemMap()
                                        .withCampaignId(campaignId2)
                                        .withSearchBid(PRICE_ELSE.bidLong().longValue())
                                        .withNetworkBid(CONTEXT_PRICE_ELSE.bidLong().longValue())
                        ),
                KeywordBidExpectedResult.successWithCampaignId(),
                KeywordBidExpectedResult.successWithCampaignId());

        BidsRecord bids1 = api.userSteps.getDirectJooqDbSteps().useShard(shard).bidsSteps().getBidById(keywordId1);;
        assertThat("у первой фразы обновилась ставка на поиске",
                bids1.getPrice(), comparesEqualTo(PRICE.bigDecimalValue().setScale(2)));
        assertThat("у первой фразы обновилась ставка на сети",
                bids1.getPriceContext(), comparesEqualTo(CONTEXT_PRICE.bigDecimalValue().setScale(2)));
        BidsRecord bids2 = api.userSteps.getDirectJooqDbSteps().bidsSteps().getBidById(keywordId2);
        assertThat("у второй фразы обновилась ставка на поиске",
                bids2.getPrice(), comparesEqualTo(PRICE_ELSE.bigDecimalValue().setScale(2)));
        assertThat("у второй фразы обновилась ставка на сети",
                bids2.getPriceContext(), comparesEqualTo(CONTEXT_PRICE_ELSE.bigDecimalValue().setScale(2)));
    }

    @Test
    @TestCaseId("2916")
    public void setWithTwoAdGroupsFromDifferentCampaigns() {
        api.userSteps.keywordBidsSteps().shouldGetKeywordBidResultOnSet(
                new SetRequestMap()
                        .withKeywordBids(new KeywordBidsSetItemMap()
                                        .withAdGroupId(adGroupId1)
                                        .withSearchBid(PRICE.bidLong().longValue())
                                        .withNetworkBid(CONTEXT_PRICE.bidLong().longValue()),
                                new KeywordBidsSetItemMap()
                                        .withAdGroupId(adGroupId2)
                                        .withSearchBid(PRICE_ELSE.bidLong().longValue())
                                        .withNetworkBid(CONTEXT_PRICE_ELSE.bidLong().longValue())
                        ),
                KeywordBidExpectedResult.successWithAdGroupId(),
                KeywordBidExpectedResult.successWithAdGroupId());

        BidsRecord bids1 = api.userSteps.getDirectJooqDbSteps().useShard(shard).bidsSteps().getBidById(keywordId1);
        assertThat("у первой фразы обновилась ставка на поиске",
                bids1.getPrice(), comparesEqualTo(PRICE.bigDecimalValue().setScale(2)));
        assertThat("у первой фразы обновилась ставка на сети",
                bids1.getPriceContext(), comparesEqualTo(CONTEXT_PRICE.bigDecimalValue().setScale(2)));
        BidsRecord bids2 = api.userSteps.getDirectJooqDbSteps().bidsSteps().getBidById(keywordId2);
        assertThat("у второй фразы обновилась ставка на поиске",
                bids2.getPrice(), comparesEqualTo(PRICE_ELSE.bigDecimalValue().setScale(2)));
        assertThat("у второй фразы обновилась ставка на сети",
                bids2.getPriceContext(), comparesEqualTo(CONTEXT_PRICE_ELSE.bigDecimalValue().setScale(2)));
    }

    @Test
    @TestCaseId("2917")
    public void setWithTwoKeywordsFromDifferentCampaigns() {
        api.userSteps.keywordBidsSteps().shouldGetKeywordBidResultOnSet(
                new SetRequestMap()
                        .withKeywordBids(new KeywordBidsSetItemMap()
                                        .withKeywordId(keywordId1)
                                        .withSearchBid(PRICE.bidLong().longValue())
                                        .withNetworkBid(CONTEXT_PRICE.bidLong().longValue()),
                                new KeywordBidsSetItemMap()
                                        .withKeywordId(keywordId2)
                                        .withSearchBid(PRICE_ELSE.bidLong().longValue())
                                        .withNetworkBid(CONTEXT_PRICE_ELSE.bidLong().longValue())
                        ),
                KeywordBidExpectedResult.successWithKeywordId(),
                KeywordBidExpectedResult.successWithKeywordId());

        BidsRecord bids1 = api.userSteps.getDirectJooqDbSteps().useShard(shard).bidsSteps().getBidById(keywordId1);
        assertThat("у первой фразы обновилась ставка на поиске",
                bids1.getPrice(), comparesEqualTo(PRICE.bigDecimalValue().setScale(2)));
        assertThat("у первой фразы обновилась ставка на сети",
                bids1.getPriceContext(), comparesEqualTo(CONTEXT_PRICE.bigDecimalValue().setScale(2)));
        BidsRecord bids2 = api.userSteps.getDirectJooqDbSteps().bidsSteps().getBidById(keywordId2);
        assertThat("у второй фразы обновилась ставка на поиске",
                bids2.getPrice(), comparesEqualTo(PRICE_ELSE.bigDecimalValue().setScale(2)));
        assertThat("у второй фразы обновилась ставка на сети",
                bids2.getPriceContext(), comparesEqualTo(CONTEXT_PRICE_ELSE.bigDecimalValue().setScale(2)));
    }

    @Test
    @TestCaseId("2918")
    public void setWithTwoKeywordsFromOneCampaignOneKeywordFromOther() {
        Long keywordId1Else = api.userSteps.keywordsSteps().addKeyword(adGroupId1, KEYWORD_ELSE);
        api.userSteps.keywordBidsSteps().shouldGetKeywordBidResultOnSet(
                new SetRequestMap()
                        .withKeywordBids(new KeywordBidsSetItemMap()
                                        .withKeywordId(keywordId1)
                                        .withSearchBid(PRICE.bidLong().longValue())
                                        .withNetworkBid(CONTEXT_PRICE.bidLong().longValue()),
                                new KeywordBidsSetItemMap()
                                        .withKeywordId(keywordId1Else)
                                        .withSearchBid(PRICE.bidLong().longValue())
                                        .withNetworkBid(CONTEXT_PRICE.bidLong().longValue()),
                                new KeywordBidsSetItemMap()
                                        .withKeywordId(keywordId2)
                                        .withSearchBid(PRICE_ELSE.bidLong().longValue())
                                        .withNetworkBid(CONTEXT_PRICE_ELSE.bidLong().longValue())
                        ),
                KeywordBidExpectedResult.successWithKeywordId(),
                KeywordBidExpectedResult.successWithKeywordId(),
                KeywordBidExpectedResult.successWithKeywordId());

        BidsRecord bids1 = api.userSteps.getDirectJooqDbSteps().useShard(shard).bidsSteps().getBidById(keywordId1);
        assertThat("у первой фразы обновилась ставка на поиске",
                bids1.getPrice(), comparesEqualTo(PRICE.bigDecimalValue().setScale(2)));
        assertThat("у первой фразы обновилась ставка на сети",
                bids1.getPriceContext(), comparesEqualTo(CONTEXT_PRICE.bigDecimalValue().setScale(2)));
        BidsRecord bidsElse = api.userSteps.getDirectJooqDbSteps().bidsSteps().getBidById(keywordId1Else);
        assertThat("у первой фразы обновилась ставка на поиске",
                bidsElse.getPrice(), comparesEqualTo(PRICE.bigDecimalValue().setScale(2)));
        assertThat("у первой фразы обновилась ставка на сети",
                bidsElse.getPriceContext(), comparesEqualTo(CONTEXT_PRICE.bigDecimalValue().setScale(2)));
        BidsRecord bids2 = api.userSteps.getDirectJooqDbSteps().bidsSteps().getBidById(keywordId2);
        assertThat("у второй фразы обновилась ставка на поиске",
                bids2.getPrice(), comparesEqualTo(PRICE_ELSE.bigDecimalValue().setScale(2)));
        assertThat("у второй фразы обновилась ставка на сети",
                bids2.getPriceContext(), comparesEqualTo(CONTEXT_PRICE_ELSE.bigDecimalValue().setScale(2)));
    }
}
