package ru.yandex.autotests.direct.api.campaigns.update.mobilecampaign.strategy.bids;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import com.yandex.direct.api.v5.keywords.KeywordGetItem;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

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.tables.records.BidsManualPricesRecord;
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.tags.TagDictionary;
import ru.yandex.autotests.directapi.apiclient.config.Semaphore;
import ru.yandex.autotests.directapi.model.api5.bids.BidSetItemMap;
import ru.yandex.autotests.directapi.model.api5.bids.SetRequestMap;
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.MobileAppCampaignAddItemMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.MobileAppCampaignNetworkStrategyAddMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.MobileAppCampaignNetworkStrategyMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.MobileAppCampaignSearchStrategyAddMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.MobileAppCampaignSearchStrategyMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.MobileAppCampaignStrategyAddMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.MobileAppCampaignStrategyMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.MobileAppCampaignUpdateItemMap;
import ru.yandex.autotests.directapi.model.api5.keywords.KeywordGetItemMap;
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.Step;
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.beanEquivalentV5;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assumeThat;

@Aqua.Test
@Features(CampaignsFeatures.UPDATE)
@RunWith(Parameterized.class)
@Description("Проверка возможных изменений ставок при переходе с ручных стратегий на автоматические на поиске/сети")
@Tag(TagDictionary.TRUNK)
public class StrategyManualToAutoChangeBidsTest {
    private static final String CLIENT = CampaignsLogins.CLIENT;
    private static final Currency currency = Currency.RUB;
    private static MoneyCurrency moneyCurrency = MoneyCurrency.get(currency);

    private Long campaignId;
    private Long keywordId;
    private static final Money defaultBid = moneyCurrency.getMinPrice();

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

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

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

    @Parameterized.Parameter
    public String description;

    @Parameterized.Parameter(value = 1)
    public MobileAppCampaignSearchStrategyAddMap searchStrategyPrevious;

    @Parameterized.Parameter(value = 2)
    public MobileAppCampaignNetworkStrategyAddMap networkStrategyPrevious;

    @Parameterized.Parameter(value = 3)
    public MobileAppCampaignSearchStrategyMap searchStrategy;

    @Parameterized.Parameter(value = 4)
    public MobileAppCampaignNetworkStrategyMap networkStrategy;

    @Parameterized.Parameter(value = 5)
    public Money expectedBid;

    @Parameterized.Parameter(value = 6)
    public Money expectedContextBid;

    @Parameterized.Parameters(name = "test = {0}")
    public static Collection strategies() {
        Object[][] data = new Object[][]{
                {"Ручная - ServingOff -> Авто - ServingOff",
                        new MobileAppCampaignSearchStrategyAddMap().defaultHighestPosition(),
                        new MobileAppCampaignNetworkStrategyAddMap().defaultServingOff(),
                        new MobileAppCampaignSearchStrategyMap().defaultWbMaximumClicks(currency),
                        new MobileAppCampaignNetworkStrategyMap().defaultServingOff(),
                        defaultBid.getNext(),
                        defaultBid},
                {"Ручная - ServingOff -> Авто - Default",
                        new MobileAppCampaignSearchStrategyAddMap().defaultHighestPosition(),
                        new MobileAppCampaignNetworkStrategyAddMap().defaultServingOff(),
                        new MobileAppCampaignSearchStrategyMap().defaultWbMaximumClicks(currency),
                        new MobileAppCampaignNetworkStrategyMap().defaultNetworkDefault(),
                        defaultBid.getNext(),
                        defaultBid},
                {"ServingOff - Max -> ServingOff - Авто",
                        new MobileAppCampaignSearchStrategyAddMap().defaultServingOff(),
                        new MobileAppCampaignNetworkStrategyAddMap().defaultMaximumCoverage(),
                        new MobileAppCampaignSearchStrategyMap().defaultServingOff(),
                        new MobileAppCampaignNetworkStrategyMap().defaultWbMaximumClicks(currency),
                        defaultBid,
                        defaultBid.getNext()},
                {"Ручная - ServingOff -> ServingOff - Авто",
                        new MobileAppCampaignSearchStrategyAddMap().defaultHighestPosition(),
                        new MobileAppCampaignNetworkStrategyAddMap().defaultServingOff(),
                        new MobileAppCampaignSearchStrategyMap().defaultServingOff(),
                        new MobileAppCampaignNetworkStrategyMap().defaultWbMaximumClicks(currency),
                        defaultBid.getNext(),
                        defaultBid},
                {"Ручная - Max -> ServingOff - Авто",
                        new MobileAppCampaignSearchStrategyAddMap().defaultHighestPosition(),
                        new MobileAppCampaignNetworkStrategyAddMap().defaultMaximumCoverage(),
                        new MobileAppCampaignSearchStrategyMap().defaultServingOff(),
                        new MobileAppCampaignNetworkStrategyMap().defaultWbMaximumClicks(currency),
                        defaultBid.getNext(),
                        defaultBid.getNext()},
                {"Ручная - Max -> Авто - ServingOff",
                        new MobileAppCampaignSearchStrategyAddMap().defaultHighestPosition(),
                        new MobileAppCampaignNetworkStrategyAddMap().defaultMaximumCoverage(),
                        new MobileAppCampaignSearchStrategyMap().defaultWbMaximumClicks(currency),
                        new MobileAppCampaignNetworkStrategyMap().defaultServingOff(),
                        defaultBid.getNext(),
                        defaultBid.getNext()}
        };
        return Arrays.asList(data);
    }

    @Before
    @Step("Подготовим данные для теста")
    public void clearUnits() {
        api.userSteps.clientFakeSteps().fakeClearClientSpentUnits(CLIENT);
        List<Long> ids = api.userSteps.campaignStepsV5().campaignsAddWithCheck(new CampaignAddItemMap()
                .defaultCampaignAddItem()
                .withMobileAppCampaign(new MobileAppCampaignAddItemMap()
                        .withBiddingStrategy(new MobileAppCampaignStrategyAddMap()
                                .withSearch(searchStrategyPrevious)
                                .withNetwork(networkStrategyPrevious))));
        assumeThat("создана кампания", ids, hasSize(1));
        campaignId = ids.get(0);
        Long groupId = api.userSteps.adGroupsSteps().addDefaultMobileGroup(campaignId);
        api.userSteps.adsSteps().addDefaultMobileAppAd(groupId);
        keywordId = api.userSteps.keywordsSteps().addDefaultKeyword(groupId);

        api.userSteps.bidsSteps().bidsSet(new SetRequestMap().withBids(
                new BidSetItemMap()
                        .withKeywordId(keywordId)
                        .withBid(defaultBid.getNext().bidLong().longValue())
                        .withContextBid(defaultBid.getNext().bidLong().longValue())), null);
    }

    @Test
    public void bidChangeOnStrategyUpdateTest() {
        api.userSteps.campaignStepsV5().campaignsUpdateWithCheck(new CampaignUpdateItemMap()
                .withId(campaignId)
                .withMobileAppCampaign(new MobileAppCampaignUpdateItemMap()
                        .withBiddingStrategy(new MobileAppCampaignStrategyMap()
                                .withSearch(searchStrategy)
                                .withNetwork(networkStrategy))));
        List<KeywordGetItem> keywords = api.userSteps.keywordsSteps().keywordsGetById(keywordId);
        assumeThat("получили ключевое слово", keywords, hasSize(1));

        KeywordGetItemMap expectedKeyword = new KeywordGetItemMap()
                .withBid(expectedBid.bidLong().longValue())
                .withContextBid(expectedContextBid.bidLong().longValue());
        BidsManualPricesRecord priceReserve = api.userSteps.getDirectJooqDbSteps().useShardForLogin(CLIENT)
                .bidsManualPricesSteps().getBidsManualPrices(campaignId, BigInteger.valueOf(keywordId));

        assertThat("корректные ставки ключевого слова", keywords.get(0), beanEquivalentV5(expectedKeyword.getBean()));
        assertThat("ставки перенеслись в резерв таблицы bids_manual_prices", priceReserve, notNullValue());
    }
}
