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

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

import com.yandex.direct.api.v5.general.PriorityEnum;
import com.yandex.direct.api.v5.keywords.KeywordGetItem;
import org.hamcrest.Matcher;
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.TextCampaignAddItemMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.TextCampaignNetworkStrategyAddMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.TextCampaignNetworkStrategyMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.TextCampaignSearchStrategyAddMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.TextCampaignSearchStrategyMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.TextCampaignStrategyAddMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.TextCampaignStrategyMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.TextCampaignUpdateItemMap;
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.autotests.irt.testutils.beandiffer.matchvariation.DefaultMatchVariation;
import ru.yandex.autotests.irt.testutils.beandiffer.matchvariation.MatchVariation;
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.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasSize;
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;
import static ru.yandex.autotests.irt.testutils.beandiffer.BeanDifferMatcher.beanEquivalent;

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

    private TextCampaignStrategyMap strategyMap;
    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 TextCampaignSearchStrategyAddMap searchStrategyPrevious;

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

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

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

    @Parameterized.Parameter(value = 5)
    public Matcher expectedBidMatcher;

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

    @Parameterized.Parameters(name = "test = {0}")
    public static Collection strategies() {
        Object[][] data = new Object[][]{
                {"Авто - Disabled -> Ручная - Disabled",
                        new TextCampaignSearchStrategyAddMap().defaultAverageCpc(currency),
                        new TextCampaignNetworkStrategyAddMap().defaultServingOff(),
                        new TextCampaignSearchStrategyMap().defaultHighestPosition(),
                        new TextCampaignNetworkStrategyMap().defaultServingOff(),
                        greaterThan(defaultBid.bidLong().longValue()),
                        defaultBid},
                {"Disabled - Авто -> Disabled - Ручная",
                        new TextCampaignSearchStrategyAddMap().defaultServingOff(),
                        new TextCampaignNetworkStrategyAddMap().defaultAverageCpc(currency),
                        new TextCampaignSearchStrategyMap().defaultServingOff(),
                        new TextCampaignNetworkStrategyMap().defaultMaximumCoverage(),
                        equalTo(Money.valueOf(0L)),
                        Money.valueOf(3L)}, // detail https://st.yandex-team.ru/DIRECT-74266#1516352605000
        };
        return Arrays.asList(data);
    }

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

        //Жесткая установка ставок в базе
        /*int shard = api.userSteps.getDBSteps().getShardingSteps().getShardByCid(campaignId);
        Bids keyword = api.userSteps.getDBSteps().getBidsSteps().getBids(keywordId, shard);
        keyword.setPrice(defaultBid.getNext().bigDecimalValue());
        keyword.setPriceContext(defaultBid.getNext().bigDecimalValue());
        api.userSteps.getDBSteps().getBidsSteps().updateBids(keyword, shard);*/

        //Установка ставок через сервис Bids
        api.userSteps.bidsSteps().bidsSet(new SetRequestMap().withBids(
                new BidSetItemMap()
                        .withKeywordId(keywordId)
                        .withStrategyPriority(PriorityEnum.HIGH)
                        .withBid(defaultBid.getNext().bidLong().longValue())
                        .withContextBid(defaultBid.getNext().bidLong().longValue())), null);
        strategyMap = new TextCampaignStrategyMap()
                .withSearch(searchStrategy)
                .withNetwork(networkStrategy);
    }

    @Test
    @ru.yandex.qatools.allure.annotations.TestCaseId("1157")
    public void bidChangeOnStrategyUpdateTest() {
        api.userSteps.campaignSteps().campaignsUpdateWithCheck(new CampaignUpdateItemMap()
                .withId(campaignId)
                .withTextCampaign(new TextCampaignUpdateItemMap()
                        .withBiddingStrategy(strategyMap)));
        List<KeywordGetItem> keywords = api.userSteps.keywordsSteps().keywordsGetById(keywordId);
        assumeThat("получили ключевое слово", keywords, hasSize(1));

        KeywordGetItemMap expectedKeyword = new KeywordGetItemMap()
                .withContextBid(expectedContextBid.bidLong().longValue());
        MatchVariation variation = new DefaultMatchVariation()
                .forFields("bids").useMatcher(expectedBidMatcher);

        BidsManualPricesRecord priceReserve = api.userSteps.getDirectJooqDbSteps().useShardForLogin(CLIENT)
                .bidsManualPricesSteps().getBidsManualPrices(campaignId, BigInteger.valueOf(keywordId));

        assertThat("корректные ставки ключевого слова", keywords.get(0),
                beanEquivalent(expectedKeyword.getBean()).withVariation(variation));
        assertThat("отсутствуют записи по ставкам в таблице bids_manual_prices", priceReserve, nullValue());
    }
}
