package ru.yandex.autotests.direct.api.audiencetargets.resume;

import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.json.simple.JSONObject;
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.audiencetargets.AudienceTargetsFeatures;
import ru.yandex.autotests.direct.api.audiencetargets.AudienceTargetsLogins;
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.apiclient.version5.ServiceNames;
import ru.yandex.autotests.directapi.model.api5.Action;
import ru.yandex.autotests.directapi.model.api5.audiencetargets.AudienceTargetAddItemMap;
import ru.yandex.autotests.directapi.model.api5.audiencetargets.ResumeRequestMap;
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.model.retargeting.RetargetingGoalType;
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.hazelcast.SemaphoreRule;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assumeThat;

/**
 * https://st.yandex-team.ru/TESTIRT-8519
 */
@Aqua.Test
@Features(AudienceTargetsFeatures.RESUME)
@Description("Проверка списания баллов")
@Issue("https://st.yandex-team.ru/DIRECT-48447")
public class ResumeAudienceTargetsUnitsTest {
    private static final String LOGIN = AudienceTargetsLogins.LOGIN_TARGET42;
    private static List<Long> goalIds;

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

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

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

    private static final int CALL_COST = 10;
    private static final int RETARGETING_LIST_COST = 2;
    private static final int ERROR_COST = 20;
    private static final int COMMON_REQUEST_ERROR_COST = 50;
    private Long pid;
    private Long targetId;

    @BeforeClass
    public static void prepareGoals() {
        goalIds = api.userSteps.retargetingSteps().getRetargetingGoalIDsByType(LOGIN, RetargetingGoalType.GOAL);
        assumeThat("у клиента должно быть > 1 цели", goalIds.size(), greaterThan(1));
    }

    @Before
    public void addUnitsToClient() {
        api.userSteps.clientFakeSteps().fakeClearClientSpentUnits(LOGIN);
        api.as(LOGIN);
        Long cid = api.userSteps.campaignSteps().addDefaultTextCampaign();
        pid = api.userSteps.adGroupsSteps().addDefaultGroup(cid);
    }

    @Test
    public void resumeOneAudienceTarget() {
        Long retargetingListsId = api.userSteps.retargetingListsSteps().addDefaultRetargetingLists(goalIds.get(0));
        targetId = api.userSteps.audienceTargetsSteps().add(
                new ru.yandex.autotests.directapi.model.api5.audiencetargets.AddRequestMap()
                        .withAudienceTargets(new AudienceTargetAddItemMap()
                                .withAdGroupId(pid)
                                .withRetargetingListId(retargetingListsId)
                        )).get(0);
        api.userSteps.audienceTargetsSteps().suspend(targetId);
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(LOGIN);
        api.userSteps.audienceTargetsSteps().resume(targetId);
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(LOGIN);
        int actualCost = unitsBefore - unitsAfter;
        int expectedCost = CALL_COST + RETARGETING_LIST_COST;
        assertThat("списалось верное число баллов", actualCost, equalTo(expectedCost));
    }

    @Test
    public void resumeTwoAudienceTarget() {
        Long retargetingListsId1 = api.userSteps.retargetingListsSteps().addDefaultRetargetingLists(goalIds.get(0));
        Long retargetingListsId2 = api.userSteps.retargetingListsSteps().addDefaultRetargetingLists(goalIds.get(1));
        List<Long> targetIds = api.userSteps.audienceTargetsSteps().add(
                new ru.yandex.autotests.directapi.model.api5.audiencetargets.AddRequestMap()
                        .withAudienceTargets(
                                new AudienceTargetAddItemMap()
                                        .withAdGroupId(pid)
                                        .withRetargetingListId(retargetingListsId1),
                                new AudienceTargetAddItemMap()
                                        .withAdGroupId(pid)
                                        .withRetargetingListId(retargetingListsId2)
                        ));
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(LOGIN);
        api.userSteps.audienceTargetsSteps().resume(targetIds.get(0), targetIds.get(1));
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(LOGIN);
        int actualCost = unitsBefore - unitsAfter;
        int expectedCost = CALL_COST + RETARGETING_LIST_COST * 2;
        assertThat("списалось верное число баллов", actualCost, equalTo(expectedCost));
    }

    @Test
    public void resumeOneInvalidAudienceTarget() {
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(LOGIN);
        api.userSteps.audienceTargetsSteps().shouldGetResultOnResume(
                new ResumeRequestMap()
                        .withSelectionCriteria(new IdsCriteriaMap()
                                .withIds(-1L)),
                ExpectedResult.errors(new Notification(5005, Api5ErrorDetailsJava.ID_MUST_BE_POSITIVE_INTEGER)));
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(LOGIN);
        int actualCost = unitsBefore - unitsAfter;
        int expectedCost = CALL_COST + ERROR_COST;
        assertThat("списалось верное число баллов", actualCost, equalTo(expectedCost));
    }

    @Test
    public void resumeTwoInvalidAudienceTarget() {
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(LOGIN);
        api.userSteps.audienceTargetsSteps().shouldGetResultOnResume(
                new ResumeRequestMap()
                        .withSelectionCriteria(new IdsCriteriaMap()
                                .withIds(-1L, 1L)),
                ExpectedResult.errors(new Notification(5005, Api5ErrorDetailsJava.ID_MUST_BE_POSITIVE_INTEGER)),
                ExpectedResult.errors(new Notification(8800, Api5ErrorDetails.AUDIENCE_TARGETS_NOT_FOUND)));
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(LOGIN);
        int actualCost = unitsBefore - unitsAfter;
        int expectedCost = CALL_COST + ERROR_COST * 2;
        assertThat("списалось верное число баллов", actualCost, equalTo(expectedCost));
    }

    @Test
    public void resumeOneValidAndOneInvalidAudienceTarget() {
        Long retargetingListsId = api.userSteps.retargetingListsSteps().addDefaultRetargetingLists(goalIds.get(0));
        targetId = api.userSteps.audienceTargetsSteps().add(
                new ru.yandex.autotests.directapi.model.api5.audiencetargets.AddRequestMap()
                        .withAudienceTargets(new AudienceTargetAddItemMap()
                                .withAdGroupId(pid)
                                .withRetargetingListId(retargetingListsId)
                        )).get(0);
        api.userSteps.audienceTargetsSteps().suspend(targetId);
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(LOGIN);
        api.userSteps.audienceTargetsSteps().shouldGetResultOnResume(
                new ResumeRequestMap()
                        .withSelectionCriteria(new IdsCriteriaMap()
                                .withIds(targetId, 0L)),
                ExpectedResult.success(targetId),
                ExpectedResult.errors(new Notification(5005, Api5ErrorDetailsJava.ID_MUST_BE_POSITIVE_INTEGER)));
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(LOGIN);
        int actualCost = unitsBefore - unitsAfter;
        int expectedCost = CALL_COST + ERROR_COST + RETARGETING_LIST_COST;
        assertThat("списалось верное число баллов", actualCost, equalTo(expectedCost));
    }

    @Test
    public void invalidRequest() {
        int unitsBefore = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(LOGIN);
        JSONObject request = new JSONObject();
        JSONObject selectionCriteria = new JSONObject();
        selectionCriteria.put(StringUtils.capitalize(IdsCriteriaMap.IDS), 1L);
        request.put(StringUtils.capitalize(ResumeRequestMap.SELECTION_CRITERIA), new Object[]{selectionCriteria});
        api.userSteps.retargetingListsSteps().shouldGetJSONErrorOn(
                ServiceNames.AUDIENCE_TARGETS,
                LOGIN,
                Action.RESUME,
                request,
                new Api5Error(8000, Api5ErrorDetailsJava.FIELD_MUST_NOT_CONTAIN_ARRAY,
                        StringUtils.capitalize(ResumeRequestMap.SELECTION_CRITERIA)));
        int unitsAfter = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(LOGIN);
        int actualCost = unitsBefore - unitsAfter;
        int expectedCost = COMMON_REQUEST_ERROR_COST;
        assertThat("списалось верное число баллов", actualCost, equalTo(expectedCost));
    }

    @Test
    public void resumeAudienceTargetWhenClientHasZeroUnits() {
        Long retargetingListsId = api.userSteps.retargetingListsSteps().addDefaultRetargetingLists(goalIds.get(0));
        targetId = api.userSteps.audienceTargetsSteps().add(
                new ru.yandex.autotests.directapi.model.api5.audiencetargets.AddRequestMap()
                        .withAudienceTargets(new AudienceTargetAddItemMap()
                                .withAdGroupId(pid)
                                .withRetargetingListId(retargetingListsId)
                        )).get(0);
        int units = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(LOGIN);
        api.userSteps.clientFakeSteps().fakeWithdrawClientUnits(LOGIN, units);
        units = api.userSteps.clientFakeSteps().fakeClientUnitsBalance(LOGIN);
        assumeThat("у клиента нету баллов", units, equalTo(0));

        api.userSteps.audienceTargetsSteps().expectErrorOnAudienceTargetsResume(
                new ResumeRequestMap()
                        .withSelectionCriteria(new IdsCriteriaMap()
                                .withIds(targetId)),
                new Api5Error(152, Api5ErrorDetails.NOT_ENOUGH_UNITS_FOR_OPERATION));
    }
}
