package ru.yandex.autotests.directapi.retargetinglists.update;

import java.sql.Timestamp;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.yandex.direct.api.v5.retargetinglists.RetargetingListRuleOperatorEnum;
import org.apache.commons.lang.RandomStringUtils;
import org.joda.time.DateTime;
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.db.models.jooq.ppc.enums.RetargetingGoalsGoalType;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.RetargetingConditionsRecord;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.RetargetingGoalsRecord;
import ru.yandex.autotests.directapi.apiclient.config.Semaphore;
import ru.yandex.autotests.directapi.model.api5.retargetinglists.AddRequestMap;
import ru.yandex.autotests.directapi.model.api5.retargetinglists.RetargetingListAddItemMap;
import ru.yandex.autotests.directapi.model.api5.retargetinglists.RetargetingListRuleArgumentItemMap;
import ru.yandex.autotests.directapi.model.api5.retargetinglists.RetargetingListRuleItemMap;
import ru.yandex.autotests.directapi.model.api5.retargetinglists.RetargetingListUpdateItemMap;
import ru.yandex.autotests.directapi.model.api5.retargetinglists.UpdateRequestMap;
import ru.yandex.autotests.directapi.model.retargeting.RetargetingGoalType;
import ru.yandex.autotests.directapi.retargetinglists.RetargetingListsFeatures;
import ru.yandex.autotests.directapi.retargetinglists.RetargetingListsLogins;
import ru.yandex.autotests.directapi.rules.ApiSteps;
import ru.yandex.autotests.directapi.rules.Trashman;
import ru.yandex.autotests.irt.testutils.RandomUtils;
import ru.yandex.autotests.irt.testutils.beandiffer2.comparestrategy.defaultcomparestrategy.DefaultCompareStrategies;
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 org.hamcrest.Matchers.iterableWithSize;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static ru.yandex.autotests.direct.db.utils.JooqRecordDifferMatcher.recordDiffer;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assumeThat;

/**
 * Created by buhter on 02/03/16
 * https://st.yandex-team.ru/TESTIRT-8519
 */
@Aqua.Test
@Features(RetargetingListsFeatures.UPDATE)
@Description("Проверка корректности записи в базу после Update")
@Issue("https://st.yandex-team.ru/DIRECT-48447")

public class UpdateRetargetingListsAndCheckDBTest {
    private static Long retCondId;
    private static final Integer CORRECT_LIFESPAN = RandomUtils.getRandomInteger(1, 60);
    private static final Integer ANOTHER_CORRECT_LIFESPAN = CORRECT_LIFESPAN + 10;
    private static long correctGoalId;
    private static long anotherCorrectGoalId;
    private static final String NAME = "Name" + RandomStringUtils.randomAlphanumeric(5);
    private static final String ANOTHER_NAME = "Another" + NAME;
    private static final String DESCRIPTION = "Description";
    private static final String ANOTHER_DESCRIPTION = "Another Description";
    private static final RetargetingListRuleOperatorEnum OPERATOR_ENUM = RetargetingListRuleOperatorEnum.ANY;
    private static final RetargetingListRuleOperatorEnum ANOTHER_OPERATOR_ENUM = RetargetingListRuleOperatorEnum.ALL;

    private static final String CONDITION_JSON_GOALS = "goals";
    private static final String CONDITION_JSON_GOAL_ID = "goal_id";
    private static final String CONDITION_JSON_TIME = "time";
    private static final String CONDITION_JSON_TYPE = "type";
    private static final String LOGIN = RetargetingListsLogins.LOGIN_RETARGETING24;
    private static Timestamp modTime;

    @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 JsonObject conditionJson;
    private static RetargetingGoalsRecord retargetingGoals;
    private static RetargetingConditionsRecord retargetingConditionsRecord;

    @BeforeClass
    public static void prepare() {
        api.userSteps.deleteAllRetargetingListsByLogin(LOGIN);

        api.userSteps.clientFakeSteps().fakeClearClientSpentUnits(LOGIN);
        int shard = api.userSteps.clientFakeSteps().getUserShard(LOGIN);
        List<Long> goalIds = api.userSteps.retargetingSteps().getRetargetingGoalIDsByType(LOGIN,
                RetargetingGoalType.GOAL);
        assumeThat("получено больше 1 объекта", goalIds.size(), greaterThan(1));
        correctGoalId = goalIds.get(0);
        anotherCorrectGoalId = goalIds.get(1);
        List<Long> idList = api.userSteps.retargetingListsSteps().add(new AddRequestMap()
                .withRetargetingLists(
                        new RetargetingListAddItemMap()
                                .withDescription(DESCRIPTION)
                                .withName(NAME)
                                .withRules(new RetargetingListRuleItemMap()
                                        .withOperator(OPERATOR_ENUM)
                                        .withArgumentItems(new RetargetingListRuleArgumentItemMap()
                                                .withMembershipLifeSpan(CORRECT_LIFESPAN)
                                                .withExternalId(correctGoalId))))
        );
        assumeThat("добавился один объект", idList, iterableWithSize(1));
        retCondId = idList.get(0);
        modTime = new Timestamp(DateTime.now().minusMinutes(1).getMillis());
        RetargetingConditionsRecord retargetingConditionsRecordTemp =
                api.userSteps.getDirectJooqDbSteps().useShard(shard)
                .retargetingConditionSteps().getRetargeingConditionByRetCondId(retCondId);
        retargetingConditionsRecordTemp.setModtime(modTime);
        api.userSteps.getDirectJooqDbSteps().useShard(shard).retargetingConditionSteps()
                .addRetargetingCondition(
                        retargetingConditionsRecordTemp,
                        Long.valueOf(api.userSteps.clientFakeSteps().getClientData(LOGIN).getClientID()));
        api.userSteps.retargetingListsSteps().update(new UpdateRequestMap()
                .withRetargetingLists(
                        new RetargetingListUpdateItemMap()
                                .withId(retCondId)
                                .withDescription(ANOTHER_DESCRIPTION)
                                .withName(ANOTHER_NAME)
                                .withRules(
                                        new RetargetingListRuleItemMap()
                                                .withOperator(ANOTHER_OPERATOR_ENUM)
                                                .withArgumentItems(
                                                        new RetargetingListRuleArgumentItemMap()
                                                                .withMembershipLifeSpan(ANOTHER_CORRECT_LIFESPAN)
                                                                .withExternalId(anotherCorrectGoalId)
                                                )
                                )
                ));
        retargetingGoals = api.userSteps.getDirectJooqDbSteps().useShard(shard).retargetingGoalsSteps()
                .getRetargetingGoals(retCondId, anotherCorrectGoalId);
        retargetingConditionsRecord = api.userSteps.getDirectJooqDbSteps().useShard(shard).retargetingConditionSteps()
                .getRetargeingConditionByRetCondId(retCondId);

        assumeThat("в таблицу ppc.retargeting_conditions добавилась запись", retargetingConditionsRecord,
                notNullValue());
        conditionJson = new Gson().fromJson(retargetingConditionsRecord.getConditionJson(), JsonElement.class)
                .getAsJsonArray().get(0).getAsJsonObject();
    }

    @Test
    public void testAddAndCheckDBRetargetingGoals() {
        RetargetingGoalsRecord expectedRetargetingGoals = new RetargetingGoalsRecord()
                .setRetCondId(retCondId)
                .setGoalId(anotherCorrectGoalId)
                .setIsAccessible(1)
                .setGoalType(RetargetingGoalsGoalType.goal);
        assertThat("в базу записался объект", retargetingGoals,
                recordDiffer(expectedRetargetingGoals).useCompareStrategy(DefaultCompareStrategies.onlyExpectedFields()));
    }

    @Test
    public void testAddAndCheckDBRetargetingConditions() {
        RetargetingConditionsRecord expectedRetargetingConditionsRecord = new RetargetingConditionsRecord();
        expectedRetargetingConditionsRecord.setRetCondId(retCondId);
        expectedRetargetingConditionsRecord.setClientid(Long.valueOf(api.userSteps.clientFakeSteps().getClientData(LOGIN).getClientID()));
        expectedRetargetingConditionsRecord.setConditionName(ANOTHER_NAME);
        expectedRetargetingConditionsRecord.setConditionDesc(ANOTHER_DESCRIPTION);
        expectedRetargetingConditionsRecord.setIsDeleted(0);
        assertThat("в базу записался объект", retargetingConditionsRecord,
                recordDiffer(expectedRetargetingConditionsRecord).useCompareStrategy(DefaultCompareStrategies.onlyExpectedFields()));

    }

    @Test
    public void checkModtimeUpdate() {
        assertThat("значение modtime обновилось", retargetingConditionsRecord.getModtime(), not(equalTo(modTime)));
    }

    @Test
    public void testAddAndCheckDBRetargetingConditionsGoalId() {
        long goalIdInDB = conditionJson.
                get(CONDITION_JSON_GOALS).getAsJsonArray().get(0).getAsJsonObject().
                get(CONDITION_JSON_GOAL_ID).getAsLong();

        assertThat("в базу записался объект", goalIdInDB, equalTo(anotherCorrectGoalId));
    }

    @Test
    public void testAddAndCheckDBRetargetingConditionsType() {
        String typeInDB = conditionJson.getAsJsonObject().get(CONDITION_JSON_TYPE).getAsString();

        assertThat("в базу записался объект", typeInDB, equalTo("all"));
    }

    @Test
    public void testAddAndCheckDBRetargetingConditionsTime() {
        long timeInDB = conditionJson.get(CONDITION_JSON_GOALS).getAsJsonArray()
                .get(0).getAsJsonObject().get(CONDITION_JSON_TIME).getAsLong();

        assertThat("в базу записался объект", timeInDB, equalTo(ANOTHER_CORRECT_LIFESPAN.longValue()));
    }
}
