package ru.yandex.autotests.direct.api.bidmodifiers.delete;

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.bidmodifiers.BidModifiersFeatures;
import ru.yandex.autotests.direct.api.bidmodifiers.BidModifiersLogins;
import ru.yandex.autotests.direct.utils.tags.TagDictionary;
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.apiclient.errors.Api5ErrorDetailsJava;
import ru.yandex.autotests.directapi.model.api5.Action;
import ru.yandex.autotests.directapi.model.api5.bidmodifiers.DeleteRequestMap;
import ru.yandex.autotests.directapi.model.api5.general.ExpectedResult;
import ru.yandex.autotests.directapi.model.api5.general.IdsCriteriaMap;
import ru.yandex.autotests.directapi.model.api5.general.Notification;
import ru.yandex.autotests.directapi.rules.ApiSteps;
import ru.yandex.autotests.directapi.rules.Trashman;
import ru.yandex.autotests.irt.testutils.allure.LogSteps;
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.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 chicos on 31.07.15
 */
@Aqua.Test
@Features(BidModifiersFeatures.DELETE)
@Tag(TagDictionary.TRUNK)
@Stories(ApiStories.UNITS)
@Description("Списание баллов при удалении корректировок ставок")
public class DeleteBidModifiersUnitsTest {
    private LogSteps log = LogSteps.getLogger(this.getClass());
    private static final String client = BidModifiersLogins.CLIENT_UNITS_DELETE;

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

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

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

    private static final int DELETE_COST = 15;
    private static final int ITEM_COST_ON_DELETE = 0;
    private static final int ITEM_COST_ON_DELETE_FAULT = 0;
    private static final int GENERAL_FAULT_COST = 50;

    private static final Long INVALID_ID = 123456L;
    private static final Long INVALID_ID_2 = 123457L;

    private long groupID;
    private static Long campaignID;

    @BeforeClass
    public static void prepareCampaign() {
        api.userSteps.clientFakeSteps().fakeClearClientSpentUnits(client);
        campaignID = api.userSteps.campaignSteps().addDefaultTextCampaign(client);
    }

    @Before
    public void prepareGroup() {
        api.userSteps.clientFakeSteps().fakeClearClientSpentUnits(client);
        groupID = api.userSteps.adGroupsSteps().addDefaultGroup(campaignID);
    }

    @Test
    @Description("Удаление одиночной корректировки ставок")
    public void deleteSingleBidModifier() {
        Long bmId = api.userSteps.bidModifiersSteps().addBidModifierDemographicsToGroup(groupID);

        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.bidModifiersSteps().bidModifiersDelete(bmId);
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);

        assertThat("стоимость удаления одной корректировки ставок", unitsBefore - unitsAfter, equalTo(DELETE_COST + ITEM_COST_ON_DELETE));
    }

    @Test
    @Description("Удаление нескольких корректировок ставок")
    public void deleteSeveralBidModifiersTest() {
        Integer conditionId = api.userSteps.retargetingSteps().addRandomRetargetingCondition(client);
        Long bmID1 = api.userSteps.bidModifiersSteps().addBidModifierRetargetingToGroup(conditionId.longValue(), groupID);
        Long bmID2 = api.userSteps.bidModifiersSteps().addBidModifierDemographicsToGroup(groupID);

        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.bidModifiersSteps().bidModifiersDelete(bmID1, bmID2);
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);

        assertThat("стоимость удаления двух корректировок ставок", unitsBefore - unitsAfter, equalTo(DELETE_COST + ITEM_COST_ON_DELETE * 2));
    }

    @Test
    @Description("Удаление одного невалидной корректировки ставок")
    public void deleteInvalidBidModifierTest() {
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.bidModifiersSteps().shouldGetResultOn(
                Action.DELETE,
                new DeleteRequestMap()
                        .withSelectionCriteria(new IdsCriteriaMap()
                                .withIds(INVALID_ID)),
                ExpectedResult.errors(new Notification(8800, Api5ErrorDetails.BID_MODIFIER_NOT_FOUND)));
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);

        assertThat("стоимость ошибки при удалении корректировки ставки", unitsBefore - unitsAfter, equalTo(DELETE_COST + ITEM_COST_ON_DELETE_FAULT));
    }

    @Test
    @Description("Удаление двух невалидных корректировок ставок")
    public void deleteFewInvalidBidModifiersTest() {
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.bidModifiersSteps().shouldGetResultOn(
                Action.DELETE,
                new DeleteRequestMap()
                        .withSelectionCriteria(new IdsCriteriaMap()
                                .withIds(INVALID_ID, INVALID_ID_2)),
                ExpectedResult.errors(new Notification(8800, Api5ErrorDetails.BID_MODIFIER_NOT_FOUND)),
                ExpectedResult.errors(new Notification(8800, Api5ErrorDetails.BID_MODIFIER_NOT_FOUND)));
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);

        assertThat("стоимость ошибки при удалении двух корректировок ставок", unitsBefore - unitsAfter,
                equalTo(DELETE_COST + ITEM_COST_ON_DELETE_FAULT * 2));
    }

    @Test
    @Description("Удаление одной корректной и одной невалидной корректировки ставок")
    public void deleteOneValidAndOneInvalidBidModifiersTest() {
        Long bmId = api.userSteps.bidModifiersSteps().addBidModifierDemographicsToGroup(groupID);

        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.bidModifiersSteps().shouldGetResultOn(
                Action.DELETE,
                new DeleteRequestMap()
                        .withSelectionCriteria(new IdsCriteriaMap()
                                .withIds(bmId, INVALID_ID)),
                ExpectedResult.success(bmId),
                ExpectedResult.errors(new Notification(8800, Api5ErrorDetails.BID_MODIFIER_NOT_FOUND)));
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);

        assertThat("стоимость ошибки при удалении нескольких корректировок ставок",
                unitsBefore - unitsAfter, equalTo(DELETE_COST + ITEM_COST_ON_DELETE + ITEM_COST_ON_DELETE_FAULT));
    }

    @Test
    @Description("Невалидный запрос на удаление корректировок ставок")
    public void generalErrorOnDeleteBidModifierTest() {
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        api.userSteps.bidModifiersSteps().shouldGetBidModifierErrorOn(
                Action.DELETE,
                new DeleteRequestMap().withSelectionCriteria(null),
                new Api5Error(8000, Api5ErrorDetails.MISSING_REQUIRED_FIELD,
                        "params",
                        capitalize(DeleteRequestMap.SELECTION_CRITERIA)),
                new Api5Error(8000, Api5ErrorDetailsJava.MISSING_PARAMETER_VALUE,
                        capitalize(DeleteRequestMap.SELECTION_CRITERIA)));
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);

        assertThat("стоимость общей ошибки при удалении корректировки ставок", unitsBefore - unitsAfter, equalTo(GENERAL_FAULT_COST));
    }

    @Test
    @Description("Недостаточное колличество баллов при удалении корректировки ставок")
    public void notEnoughUnitsOnDeleteBidModifierTest() {
        Long bmId = api.userSteps.bidModifiersSteps().addBidModifierMobileToGroup(groupID);

        log.info("Обнулим колличество доступных пользователю баллов");
        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.bidModifiersSteps().shouldGetBidModifierErrorOn(
                Action.DELETE,
                new DeleteRequestMap()
                        .withSelectionCriteria(new IdsCriteriaMap()
                                .withIds(bmId)),
                new Api5Error(152, Api5ErrorDetails.NOT_ENOUGH_UNITS_FOR_OPERATION));
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(client);
        assertThat("доступные баллы пользователя после ошибки", unitsAfter, equalTo(0));
    }
}
