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

import java.util.List;
import ru.yandex.qatools.allure.annotations.TestCaseId;

import org.apache.commons.lang3.StringUtils;
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.utils.money.Currency;
import ru.yandex.autotests.directapi.ApiStories;
import ru.yandex.autotests.directapi.apiclient.config.Semaphore;
import ru.yandex.autotests.directapi.apiclient.errors.Api5Error;
import ru.yandex.autotests.directapi.apiclient.errors.Api5ErrorDetails;
import ru.yandex.autotests.directapi.model.api5.campaigns.CampaignUpdateItemMap;
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.TextCampaignStrategyMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.TextCampaignUpdateItemMap;
import ru.yandex.autotests.directapi.model.api5.general.Notification;
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.model.campaigns.MetrikaGoals;
import ru.yandex.autotests.directapi.rules.ApiSteps;
import ru.yandex.autotests.directapi.rules.Trashman;
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.Stories;
import ru.yandex.qatools.hazelcast.SemaphoreRule;

import static org.apache.commons.lang3.StringUtils.capitalize;
import static org.hamcrest.Matchers.equalTo;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assumeThat;

/**
 * Created by ginger on 01.06.15.
 */
@Aqua.Test
@Stories(ApiStories.UNITS)
@Issue("https://st.yandex-team.ru/DIRECT-37056")
@Features(KeywordBidsFeatures.SET)
@Description("Проверка списания баллов.")
public class BidsSetUnitsTest {
    private static String client = BidsLogins.UNITS_SET_CLIENT;

    @ClassRule
    public static ApiSteps api = new ApiSteps().as(client);
    @ClassRule
    public static SemaphoreRule semaphore = Semaphore.getSemaphore();
    private static Long adGroupId11;
    private static List<Long> keywordIds1;
    private static Long adGroupId12;

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

    static Long campaignId1;
    static Long campaignId2;

    int SET_COST = 25;
    int SET_COST_KEYWORD = 0;

    int DEFAULT_ERROR_COST = 20;
    int DEFAULT_FAULT_COST = 50;

    @BeforeClass
    public static void initTest() {

        campaignId1 = api.userSteps.campaignSteps().addDefaultTextCampaignWithStrategies(
                new TextCampaignSearchStrategyAddMap().defaultHighestPosition(),
                new TextCampaignNetworkStrategyAddMap().defaultMaximumCoverage(),
                client
        );
        adGroupId11 = api.userSteps.adGroupsSteps().addDefaultGroup(campaignId1, client);
        api.userSteps.adsSteps().addDefaultTextAd(adGroupId11, client);
        keywordIds1 = api.userSteps.keywordsSteps().addDefaultKeywords(client, adGroupId11, 2);

        adGroupId12 = api.userSteps.adGroupsSteps().addDefaultGroup(campaignId1, client);
        api.userSteps.adsSteps().addDefaultTextAd(adGroupId12, client);
        api.userSteps.keywordsSteps().addDefaultKeywords(client, adGroupId12, 2);
        campaignId2 = api.userSteps.campaignSteps().addDefaultTextCampaignWithStrategies(
                new TextCampaignSearchStrategyAddMap().defaultHighestPosition(),
                new TextCampaignNetworkStrategyAddMap().defaultMaximumCoverage(),
                client
        );
        Long adGroupId21 = api.userSteps.adGroupsSteps().addDefaultGroup(campaignId2, client);
        api.userSteps.adsSteps().addDefaultTextAd(adGroupId21, client);
        api.userSteps.keywordsSteps().addDefaultKeywords(client, adGroupId21, 2);
    }

    @Before
    public void clearSpentUnits() {
        api.userSteps.clientFakeSteps().fakeClearClientSpentUnits(client);
    }


    @Test
    @TestCaseId("2836")
    public void setOneKeyword() {
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.keywordBidsSteps().shouldGetKeywordBidResultOnSet(
                new SetRequestMap().withKeywordBids(
                        new KeywordBidsSetItemMap()
                                .withKeywordId(keywordIds1.get(0))
                                .withSearchBid(1110000L)
                                .withNetworkBid(1110000L)),
                client,
                new KeywordBidExpectedResult().successWithKeywordId()
        );
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        assertThat("списалось правильное количество баллов",
                unitsBefore - unitsAfter, equalTo(SET_COST + SET_COST_KEYWORD));
    }

    @Test
    @TestCaseId("2837")
    public void setTwoBids() {
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.keywordBidsSteps().shouldGetKeywordBidResultOnSet(
                new SetRequestMap().withKeywordBids(
                        new KeywordBidsSetItemMap()
                                .withKeywordId(keywordIds1.get(0))
                                .withSearchBid(1120000L)
                                .withNetworkBid(1120000L),
                        new KeywordBidsSetItemMap()
                                .withKeywordId(keywordIds1.get(1))
                                .withSearchBid(1120000L)
                                .withNetworkBid(1120000L)),
                client,
                new KeywordBidExpectedResult().successWithKeywordId(),
                new KeywordBidExpectedResult().successWithKeywordId()
        );
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        assertThat("списалось правильное количество баллов",
                unitsBefore - unitsAfter, equalTo(SET_COST + 2 * SET_COST_KEYWORD));
    }

    @Test
    @TestCaseId("2838")
    public void setOneAdGroupIdWithTwoKeywordsBids() {
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.keywordBidsSteps().shouldGetKeywordBidResultOnSet(
                new SetRequestMap().withKeywordBids(
                        new KeywordBidsSetItemMap()
                                .withAdGroupId(adGroupId11)
                                .withSearchBid(1120000L)
                                .withNetworkBid(1120000L)),
                client,
                new KeywordBidExpectedResult().successWithAdGroupId()
        );
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        assertThat("списалось правильное количество баллов",
                unitsBefore - unitsAfter, equalTo(SET_COST + 2 * SET_COST_KEYWORD));
    }

    @Test
    @TestCaseId("2839")
    public void setTwoCampaignIdWithSixKeywordsBids() {
        //DIRECT-38677
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.keywordBidsSteps().shouldGetKeywordBidResultOnSet(
                new SetRequestMap().withKeywordBids(
                        new KeywordBidsSetItemMap()
                                .withCampaignId(campaignId1)
                                .withSearchBid(1120000L)
                                .withNetworkBid(1120000L),
                        new KeywordBidsSetItemMap()
                                .withCampaignId(campaignId2)
                                .withSearchBid(1130000L)
                                .withNetworkBid(1130000L)),
                client,
                new KeywordBidExpectedResult().successWithCampaignId(),
                new KeywordBidExpectedResult().successWithCampaignId()
        );
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        assertThat("списалось правильное количество баллов",
                unitsBefore - unitsAfter, equalTo(SET_COST + 6 * SET_COST_KEYWORD));
    }


    @Test
    @TestCaseId("2840")
    public void setOneBidWithError() {
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.keywordBidsSteps().shouldGetKeywordBidResultOnSet(
                new SetRequestMap().withKeywordBids(
                        new KeywordBidsSetItemMap()
                                .withKeywordId(1L)
                                .withSearchBid(1110000L)
                                .withNetworkBid(1110000L)),
                client,
                KeywordBidExpectedResult.errors(
                        (new Notification(8800, Api5ErrorDetails.KEYWORDS_NOT_FOUND_FOR_ID,
                                StringUtils.capitalize(KeywordBidsSetItemMap.KEYWORD_ID),
                                1)
                        ))
        );
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        assertThat("списалось правильное количество баллов",
                unitsBefore - unitsAfter, equalTo(SET_COST + DEFAULT_ERROR_COST));
    }

    @Test
    @TestCaseId("2841")
    public void setTwoBidsWithOneError() {
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.keywordBidsSteps().shouldGetKeywordBidResultOnSet(
                new SetRequestMap().withKeywordBids(
                        new KeywordBidsSetItemMap()
                                .withKeywordId(keywordIds1.get(0))
                                .withSearchBid(1110000L)
                                .withNetworkBid(1110000L),
                        new KeywordBidsSetItemMap()
                                .withKeywordId(1L)
                                .withSearchBid(1110000L)),
                client,
                KeywordBidExpectedResult.successWithKeywordId(),
                KeywordBidExpectedResult.errors(
                        (new Notification(8800, Api5ErrorDetails.KEYWORDS_NOT_FOUND_FOR_ID,
                                StringUtils.capitalize(KeywordBidsSetItemMap.KEYWORD_ID),
                                1)
                        ))
        );
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        assertThat("списалось правильное количество баллов",
                unitsBefore - unitsAfter, equalTo(SET_COST + DEFAULT_ERROR_COST + SET_COST_KEYWORD));
    }

    @Test
    @TestCaseId("2842")
    public void setTwoBidsWithTwoErrors() {
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.keywordBidsSteps().shouldGetKeywordBidResultOnSet(
                new SetRequestMap().withKeywordBids(
                        new KeywordBidsSetItemMap()
                                .withKeywordId(2L)
                                .withSearchBid(1110000L)
                                .withNetworkBid(1110000L),
                        new KeywordBidsSetItemMap()
                                .withKeywordId(1L)
                                .withSearchBid(1110000L)),
                client,
                KeywordBidExpectedResult.errors(
                        (new Notification(8800, Api5ErrorDetails.KEYWORDS_NOT_FOUND_FOR_ID,
                                StringUtils.capitalize(KeywordBidsSetItemMap.KEYWORD_ID),
                                2)
                        )),
                KeywordBidExpectedResult.errors(
                        (new Notification(8800, Api5ErrorDetails.KEYWORDS_NOT_FOUND_FOR_ID,
                                StringUtils.capitalize(KeywordBidsSetItemMap.KEYWORD_ID),
                                1)
                        ))
        );
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        assertThat("списалось правильное количество баллов",
                unitsBefore - unitsAfter, equalTo(SET_COST + 2 * DEFAULT_ERROR_COST));

    }

    /**
     * При указании ставок не списываются баллы за ошибки, связанные с несоответствием стратегии.
     */
    @Test
    @TestCaseId("2843")
    public void callSetBidsWithStrategyError() {
        //DIRECT-38677
        int shard = api.userSteps.clientFakeSteps().getUserShard(client);
        Integer goalID = MetrikaGoals.getRandom();
        Long campaignID = api.userSteps.campaignSteps().addDefaultTextCampaign(client);
        api.userSteps.getDirectJooqDbSteps().useShard(shard).campaignsSteps()
                .addCampMetrikaGoals(campaignID, goalID.longValue(), 200L, 0L);
        api.userSteps.campaignSteps().campaignsUpdateWithCheck(new CampaignUpdateItemMap()
                .withId(campaignID)
                .withTextCampaign(new TextCampaignUpdateItemMap()
                        .withBiddingStrategy(new TextCampaignStrategyMap()
                                .withSearch(new TextCampaignSearchStrategyMap().defaultWbMaximumClicks(Currency.RUB))
                                .withNetwork(new TextCampaignNetworkStrategyMap().defaultNetworkDefault()))));

        Long adGroupId = api.userSteps.adGroupsSteps().addDefaultGroup(campaignID, client);
        api.userSteps.adsSteps().addDefaultTextAd(adGroupId, client);
        long keywordId = api.userSteps.keywordsSteps().addDefaultKeyword(client, adGroupId);
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.keywordBidsSteps().shouldGetKeywordBidResultOnSet(
                new SetRequestMap()
                        .withKeywordBids(
                                new KeywordBidsSetItemMap()
                                        .withKeywordId(keywordId)
                                        .withSearchBid(2200000L)
                        ),
                client,
                KeywordBidExpectedResult.warningWithError(
                        new Notification(10160,
                                Api5ErrorDetails.BID_WILL_NOT_APPLIED_BECAUSE_OF_AUTO_STRATEGY,
                                capitalize(KeywordBidsSetItemMap.SEARCH_BID)),
                        new Notification(9600, Api5ErrorDetails.FOR_AUTO_STRATEGY_FIELD_MUST_BE_SPECIFIED,
                                capitalize(KeywordBidsSetItemMap.STRATEGY_PRIORITY))));
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        assertThat("списалось правильное количество баллов",
                unitsBefore - unitsAfter, equalTo(SET_COST));
    }


    //FAULT

    @Test
    @TestCaseId("2844")
    public void trySetBidsNotArray() {
        //   https://st.yandex-team.ru/DIRECT-38565
        //https://st.yandex-team.ru/DIRECT-43280
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.keywordBidsSteps().shouldGetErrorOnBidsSet(
                new SetRequestMap()
                        .withKeywordBids(
                                new KeywordBidsSetItemMap()
                                        .withKeywordId(keywordIds1.get(0))
                                        .withSearchBid(1100000L)
                        ),
                BidsLogins.BIDS_CLIENT,
                new Api5Error(8800, Api5ErrorDetails.UNKNOWN_LOGIN_IN_CLIENT_LOGIN));
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        assertThat("списалось правильное количество баллов",
                unitsBefore - unitsAfter, equalTo(DEFAULT_FAULT_COST));
    }


    @Test
    @TestCaseId("2845")
    public void setWithNotEnoughUnitsForActionButNotEmptyUnits() {
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.clientFakeSteps().fakeWithdrawClientUnits(client, unitsBefore);
        unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        assumeThat("доступные баллы пользователя", unitsBefore, equalTo(0));
        api.userSteps.keywordBidsSteps().shouldGetErrorOnBidsSet(
                new SetRequestMap().withKeywordBids(
                        new KeywordBidsSetItemMap()
                                .withAdGroupId(adGroupId11)
                                .withSearchBid(1120000L)
                                .withNetworkBid(1120000L)),
                client,
                new Api5Error(152, Api5ErrorDetails.NOT_ENOUGH_UNITS_FOR_OPERATION)
        );
    }


}
