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

import java.io.IOException;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yandex.direct.api.v5.campaigns.TextCampaignSearchStrategyTypeEnum;
import com.yandex.direct.api.v5.general.OperationEnum;
import com.yandex.direct.api.v5.general.YesNoEnum;
import org.junit.Before;
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.campaigns.CampaignsFeatures;
import ru.yandex.autotests.direct.api.campaigns.CampaignsLogins;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.CampOptionsRecord;
import ru.yandex.autotests.direct.utils.tags.TagDictionary;
import ru.yandex.autotests.directapi.apiclient.config.Semaphore;
import ru.yandex.autotests.directapi.apiclient.errors.Api5ErrorDetails;
import ru.yandex.autotests.directapi.apiclient.errors.Api5ErrorDetailsJava;
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.PriorityGoalsItemMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.PriorityGoalsUpdateItemMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.PriorityGoalsUpdateSettingMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.StrategyAverageCpaAddMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.StrategyPayForConversionCrrAddMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.StrategyPayForConversionCrrMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.StrategyPayForConversionMap;
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.campaigns.UpdateRequestMap;
import ru.yandex.autotests.directapi.model.api5.general.ExpectedResult;
import ru.yandex.autotests.directapi.model.api5.general.JavaOrPerlExpectedResult;
import ru.yandex.autotests.directapi.model.api5.general.Notification;
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.Tag;
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.nullValue;
import static ru.yandex.autotests.directapi.model.api5.campaigns.StrategyPayForConversionCrrAddMap.DEFAULT_CRR;
import static ru.yandex.autotests.directapi.model.api5.campaigns.StrategyPayForConversionCrrAddMap.DEFAULT_WEEKLY_SPEND_LIMIT;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;

@Aqua.Test
@Issue("https://st.yandex-team.ru/DIRECT-151192")
@Features(CampaignsFeatures.UPDATE)
@Description("Проверка выставления source для кц в зависимости от типа стратегии")
@Tag(TagDictionary.TRUNK)
public class UpdateTextCampaignWithMeaningfulGoalValueMetrikaSourceTest {
    private static final String LOGIN = CampaignsLogins.CLIENT;

    private static final Integer COUNTER_ID = MetrikaGoals.getCounterForLogin(LOGIN);
    private static final Long GOAL_ID = MetrikaGoals.getGoalForCounter(COUNTER_ID);

    private Long cid;

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

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

    @Rule
    public Trashman trasher = new Trashman(api);
    private int shard;

    ObjectMapper mapper = new ObjectMapper();

    @Before
    public void createCampaign() {
        cid = api.userSteps.campaignSteps().addCampaign(new CampaignAddItemMap()
                .defaultCampaignAddItem()
                .withTextCampaign(new TextCampaignAddItemMap()
                        .withBiddingStrategy(new TextCampaignStrategyAddMap()
                                .withSearch(new TextCampaignSearchStrategyAddMap()
                                        .withBiddingStrategyType(TextCampaignSearchStrategyTypeEnum.AVERAGE_CPA)
                                        .withAverageCpa(new StrategyAverageCpaAddMap()
                                                .withWeeklySpendLimit(1311_000_000_00L)
                                                .withAverageCpa(111_000_000_00L)
                                                .withGoalId(GOAL_ID)
                                        )
                                )
                                .withNetwork(new TextCampaignNetworkStrategyAddMap().defaultServingOff())
                        )
                )
        );
        shard = api.userSteps.clientFakeSteps().getUserShard(LOGIN);

    }

    @Test
    public void updateCrrCampaignWithMeaningfulGoalsWithMetrikaSource_SourceSaved() throws IOException {
        api.userSteps.campaignSteps()
                .shouldGetResultOnUpdate(new UpdateRequestMap()
                                .withCampaigns(new CampaignUpdateItemMap()
                                        .withId(cid)
                                        .withTextCampaign(new TextCampaignUpdateItemMap()
                                                .withCounterIds(COUNTER_ID)
                                                .withPriorityGoals(new PriorityGoalsUpdateSettingMap()
                                                        .withItems(new PriorityGoalsUpdateItemMap()
                                                                .withGoalId(GOAL_ID)
                                                                .withIsMetrikaSourceOfValue(YesNoEnum.YES)
                                                                .withValue(13_000_000L)
                                                                .withOperation(OperationEnum.SET))
                                                )
                                                .withBiddingStrategy(new TextCampaignStrategyMap()
                                                        .withSearch(new TextCampaignSearchStrategyMap()
                                                                .withBiddingStrategyType(TextCampaignSearchStrategyTypeEnum.PAY_FOR_CONVERSION_CRR)
                                                                .withPayForConversionCrr(new StrategyPayForConversionCrrMap()
                                                                        .withCrr(50)
                                                                        .withGoalId(GOAL_ID)
                                                                        .withWeeklySpendLimit(1_111_111_111L)
                                                                )
                                                        )
                                                        .withNetwork(new TextCampaignNetworkStrategyMap().defaultServingOff())
                                                )
                                        )
                                ),
                        ExpectedResult.success()
                );

        CampOptionsRecord campaignRecord =
                api.userSteps.getDirectJooqDbSteps().useShard(shard).campaignsSteps().getCampOptionsById(cid);
        String meaningfulGoals = campaignRecord.getMeaningfulGoals();
        int isMetrikaSourceOfValue = mapper.readTree(meaningfulGoals).elements().next().get(
                "is_metrika_source_of_value").asInt();
        assertThat("Источник кц соответствует ожиданиям",
                isMetrikaSourceOfValue,
                equalTo(1));
    }


    @Test
    public void updateCrrCampaignWithMeaningfulGoalsWithoutMetrikaSource_SourceNotSaved() throws IOException {
        api.userSteps.campaignSteps()
                .shouldGetResultOnUpdate(new UpdateRequestMap()
                                .withCampaigns(new CampaignUpdateItemMap()
                                        .withId(cid)
                                        .withTextCampaign(new TextCampaignUpdateItemMap()
                                                .withCounterIds(COUNTER_ID)
                                                .withPriorityGoals(new PriorityGoalsUpdateSettingMap()
                                                        .withItems(new PriorityGoalsUpdateItemMap()
                                                                .withGoalId(GOAL_ID)
                                                                .withValue(13_000_000L)
                                                                .withOperation(OperationEnum.SET))
                                                )
                                                .withBiddingStrategy(new TextCampaignStrategyMap()
                                                        .withSearch(new TextCampaignSearchStrategyMap()
                                                                .withBiddingStrategyType(TextCampaignSearchStrategyTypeEnum.PAY_FOR_CONVERSION_CRR)
                                                                .withPayForConversionCrr(new StrategyPayForConversionCrrMap()
                                                                        .withCrr(50)
                                                                        .withGoalId(GOAL_ID)
                                                                        .withWeeklySpendLimit(1_111_111_111L)
                                                                )
                                                        )
                                                        .withNetwork(new TextCampaignNetworkStrategyMap().defaultServingOff())
                                                )
                                        )
                                ),
                        ExpectedResult.success()
                );

        CampOptionsRecord campaignRecord =
                api.userSteps.getDirectJooqDbSteps().useShard(shard).campaignsSteps().getCampOptionsById(cid);
        String meaningfulGoals = campaignRecord.getMeaningfulGoals();
        JsonNode isMetrikaSourceOfValue = mapper.readTree(meaningfulGoals).elements().next().get(
                "is_metrika_source_of_value");
        assertThat("Источник кц соответствует ожиданиям",
                isMetrikaSourceOfValue,
                nullValue());
    }

    @Test
    public void updateNotCrrCampaignWithMeaningfulGoalsWithMetrikaSource_HasError() {
        JavaOrPerlExpectedResult expectedResult = JavaOrPerlExpectedResult
                .java(ExpectedResult.errors(
                        new Notification(5005, Api5ErrorDetailsJava.INVALID_VALUE_PATH_AND_VALUE,
                                "PriorityGoals[0].IsMetrikaSourceOfValue", "true"
                                )))
                .perl(ExpectedResult.errors(
                        new Notification(5005, Api5ErrorDetails.INVALID_VALUE_SOURCE_UPDATE, GOAL_ID)));

        api.userSteps.campaignSteps()
                .shouldGetResultOnUpdate(new UpdateRequestMap()
                                .withCampaigns(new CampaignUpdateItemMap()
                                        .withId(cid)
                                        .withTextCampaign(new TextCampaignUpdateItemMap()
                                                .withCounterIds(COUNTER_ID)
                                                .withPriorityGoals(new PriorityGoalsUpdateSettingMap()
                                                        .withItems(new PriorityGoalsUpdateItemMap()
                                                                .withGoalId(GOAL_ID)
                                                                .withValue(13_000_000L)
                                                                .withIsMetrikaSourceOfValue(YesNoEnum.YES)
                                                                .withOperation(OperationEnum.SET))
                                                )
                                                .withBiddingStrategy(new TextCampaignStrategyMap()
                                                        .withSearch(new TextCampaignSearchStrategyMap()
                                                                .withBiddingStrategyType(TextCampaignSearchStrategyTypeEnum.PAY_FOR_CONVERSION)
                                                                .withPayForConversion(new StrategyPayForConversionMap()
                                                                        .withCpa(13_000_000_00L)
                                                                        .withGoalId(GOAL_ID)
                                                                        .withWeeklySpendLimit(null))
                                                        )
                                                )
                                        )
                                ),
                        expectedResult
                );

    }

    @Test
    public void updateOnlyGoalsForNotCrrCampaignWithMeaningfulGoalsWithMetrikaSource_HasError() {
        JavaOrPerlExpectedResult expectedResult = JavaOrPerlExpectedResult
                .java(ExpectedResult.errors(
                        new Notification(5005, Api5ErrorDetailsJava.INVALID_VALUE_PATH_AND_VALUE,
                                "PriorityGoals[0].IsMetrikaSourceOfValue", "true"
                                )))
                .perl(ExpectedResult.errors(
                        new Notification(5005, Api5ErrorDetails.INVALID_VALUE_SOURCE_UPDATE, GOAL_ID)));

        api.userSteps.campaignSteps()
                .shouldGetResultOnUpdate(new UpdateRequestMap()
                                .withCampaigns(new CampaignUpdateItemMap()
                                        .withId(cid)
                                        .withTextCampaign(new TextCampaignUpdateItemMap()
                                                .withCounterIds(COUNTER_ID)
                                                .withPriorityGoals(new PriorityGoalsUpdateSettingMap()
                                                        .withItems(new PriorityGoalsUpdateItemMap()
                                                                .withGoalId(GOAL_ID)
                                                                .withValue(13_000_000L)
                                                                .withIsMetrikaSourceOfValue(YesNoEnum.YES)
                                                                .withOperation(OperationEnum.SET))
                                                )
                                        )
                                ),
                        expectedResult
                );

    }

    @Test
    public void updateToNotCrrCampaign_ResetSourceFlag() throws IOException {
        Long cid = api.userSteps.campaignSteps().addCampaign(new CampaignAddItemMap()
                .defaultCampaignAddItem()
                .withTextCampaign(new TextCampaignAddItemMap()
                        .withCounterIds(COUNTER_ID)
                        .withPriorityGoals(new PriorityGoalsItemMap()
                                .withGoalId(GOAL_ID)
                                .withIsMetrikaSourceOfValue(YesNoEnum.YES)
                                .withValue(13_000_000L)
                        )
                        .withBiddingStrategy(new TextCampaignStrategyAddMap()
                                .withSearch(new TextCampaignSearchStrategyAddMap()
                                        .withBiddingStrategyType(TextCampaignSearchStrategyTypeEnum.PAY_FOR_CONVERSION_CRR)
                                        .withPayForConversionCrr(new StrategyPayForConversionCrrAddMap()
                                                .withGoalId(GOAL_ID)
                                                .withCrr(DEFAULT_CRR)
                                                .withWeeklySpendLimit(DEFAULT_WEEKLY_SPEND_LIMIT)
                                        )
                                )
                                .withNetwork(new TextCampaignNetworkStrategyAddMap().defaultServingOff())
                        )
                )
        );

        api.userSteps.campaignSteps()
                .shouldGetResultOnUpdate(new UpdateRequestMap()
                                .withCampaigns(new CampaignUpdateItemMap()
                                        .withId(cid)
                                        .withTextCampaign(new TextCampaignUpdateItemMap()
                                                .withCounterIds(COUNTER_ID)
                                                .withBiddingStrategy(new TextCampaignStrategyMap()
                                                        .withSearch(new TextCampaignSearchStrategyMap()
                                                                .withBiddingStrategyType(TextCampaignSearchStrategyTypeEnum.PAY_FOR_CONVERSION)
                                                                .withPayForConversion(new StrategyPayForConversionMap()
                                                                        .withCpa(13_000_000_00L)
                                                                        .withGoalId(GOAL_ID)
                                                                        .withWeeklySpendLimit(null))
                                                        )
                                                )
                                        )
                                ),
                        ExpectedResult.success()
                );


        CampOptionsRecord campaignRecord =
                api.userSteps.getDirectJooqDbSteps().useShard(shard).campaignsSteps().getCampOptionsById(cid);
        String meaningfulGoals = campaignRecord.getMeaningfulGoals();
        JsonNode isMetrikaSourceOfValue = mapper.readTree(meaningfulGoals).elements().next().get(
                "is_metrika_source_of_value");
        assertThat("Источник кц соответствует ожиданиям",
                isMetrikaSourceOfValue,
                nullValue());

    }
}
