package ru.yandex.autotests.directapi.keywords.get;

import java.sql.Timestamp;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;

import com.yandex.direct.api.v5.keywords.GetResponse;
import com.yandex.direct.api.v5.keywords.KeywordFieldEnum;
import org.hamcrest.Matcher;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import ru.yandex.aqua.annotations.project.Aqua;
import ru.yandex.autotests.direct.db.steps.DirectJooqDbSteps;
import ru.yandex.autotests.directapi.apiclient.config.Semaphore;
import ru.yandex.autotests.directapi.keywords.KeywordsFeatures;
import ru.yandex.autotests.directapi.keywords.KeywordsLogins;
import ru.yandex.autotests.directapi.model.api5.keywords.GetRequestMap;
import ru.yandex.autotests.directapi.model.api5.keywords.KeywordGetItemMap;
import ru.yandex.autotests.directapi.model.api5.keywords.KeywordsSelectionCriteriaMap;
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.hasSize;
import static ru.yandex.autotests.directapi.matchers.beandiffer2.BeanDifferMatcherV5.beanDifferV5;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;

/**
 * Created by ginger on 04.08.16.
 * https://st.yandex-team.ru/TESTIRT-9939
 */
@Aqua.Test
@Description("Проверка фильтрации при использовании нескольких критериев (Ids + ModifiedSince)")
@Issue("https://st.yandex-team.ru/DIRECT-56416")
@Features(KeywordsFeatures.GET)
@RunWith(Parameterized.class)
public class IdsWithModifiedSinceFilterTest {

    private static final String CLIENT = KeywordsLogins.SINGLE_CLIENT1;

    private static Long campaignId;
    private static Long adGroupId;
    private static Long adGroupId2;
    private static Long keywordId1;
    private static Long keywordId2;
    private static Long autotargetingId1;
    private static Long autotargetingId2;

    @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 Instant DATE_TIME_NOW = Instant.now().truncatedTo(ChronoUnit.SECONDS);
    private static final Instant DATE_TIME_IN_FUTURE = DATE_TIME_NOW.plus(1, ChronoUnit.DAYS);
    private static final Instant DATE_TIME_1_MINUTE_AGO = DATE_TIME_NOW.minus(1, ChronoUnit.MINUTES);
    private static final Timestamp TIMESTAMP_1_MINUTE_AGO = Timestamp.from(DATE_TIME_1_MINUTE_AGO);
    private static final Instant DATE_TIME_2_MINUTES_AGO = DATE_TIME_NOW.minus(2, ChronoUnit.MINUTES);
    private static final Instant DATE_TIME_3_MINUTES_AGO = DATE_TIME_NOW.minus(3, ChronoUnit.MINUTES);
    private static final Timestamp TIMESTAMP_3_MINUTES_AGO = Timestamp.from(DATE_TIME_3_MINUTES_AGO);
    private static final Instant DATE_TIME_4_MINUTES_AGO = DATE_TIME_NOW.minus(4, ChronoUnit.MINUTES);

    @Parameterized.Parameter(0)
    public String description;

    @Parameterized.Parameter(1)
    public Instant modifiedSince;

    @Parameterized.Parameter(2)
    public Matcher matcher;

    @Parameterized.Parameters(name = "{0}")
    public static Iterable<Object[]> testData() {
        prepareKeywords();

        Object[][] data = new Object[][]{

                {"ModifiedSince до модификации обоих ключевиков и автотаргетингов",
                        DATE_TIME_4_MINUTES_AGO,
                        beanDifferV5(
                                Arrays.asList(
                                        new KeywordGetItemMap().withId(keywordId1).getBean(),
                                        new KeywordGetItemMap().withId(keywordId2).getBean(),
                                        new KeywordGetItemMap().withId(autotargetingId1).getBean(),
                                        new KeywordGetItemMap().withId(autotargetingId2).getBean()
                                ))},

                {"ModifiedSince совпадает с модификацией одного ключевика и автотаргетинга и раньше двух других",
                        DATE_TIME_3_MINUTES_AGO,
                        beanDifferV5(
                                Arrays.asList(
                                        new KeywordGetItemMap().withId(keywordId1).getBean(),
                                        new KeywordGetItemMap().withId(keywordId2).getBean(),
                                        new KeywordGetItemMap().withId(autotargetingId1).getBean(),
                                        new KeywordGetItemMap().withId(autotargetingId2).getBean()
                                ))},
                {"ModifiedSince после модификации одного ключевика и автотаргетинга и до двух других",
                        DATE_TIME_2_MINUTES_AGO,
                        beanDifferV5(
                                Arrays.asList(
                                        new KeywordGetItemMap().withId(keywordId2).getBean(),
                                        new KeywordGetItemMap().withId(autotargetingId2).getBean()
                                ))},
                {"ModifiedSince после модификации одного ключевика и одного автотаргетинга и одновременно с двумя другими",
                        DATE_TIME_1_MINUTE_AGO,
                        beanDifferV5(
                                Arrays.asList(
                                        new KeywordGetItemMap().withId(keywordId2).getBean(),
                                        new KeywordGetItemMap().withId(autotargetingId2).getBean()
                                ))},
                {"ModifiedSince после модификации обоих ключевиков и автотаргетингов", DATE_TIME_NOW, hasSize(0)},
                {"ModifiedSince в будущем", DATE_TIME_IN_FUTURE, hasSize(0)},
        };

        return Arrays.asList(data);
    }

    private static void prepareKeywords() {
        api.userSteps.clientFakeSteps().fakeClearClientSpentUnits(CLIENT);

        campaignId = api.userSteps.campaignSteps().addDefaultTextCampaign();
        adGroupId = api.userSteps.adGroupsSteps().addDefaultGroup(campaignId);
        adGroupId2 = api.userSteps.adGroupsSteps().addDefaultGroup(campaignId);

        // Используем рандомные ключевые фразы. См. TESTIRT-10286
        keywordId1 = api.userSteps.keywordsSteps()
                .addRandomKeyword(adGroupId);
        keywordId2 = api.userSteps.keywordsSteps()
                .addRandomKeyword(adGroupId);
        autotargetingId1 = api.userSteps.keywordsSteps().addAutotargeting(adGroupId);
        autotargetingId2 = api.userSteps.keywordsSteps().addAutotargeting(adGroupId2);
        DirectJooqDbSteps jooqDbSteps = api.userSteps.getDirectJooqDbSteps().useShardForLogin(CLIENT);
        jooqDbSteps.bidsBaseSteps().updateBidsBase(
                jooqDbSteps.bidsBaseSteps().getBidsBaseByBidId(autotargetingId1).setLastchange(TIMESTAMP_3_MINUTES_AGO)
        );
        jooqDbSteps.bidsBaseSteps().updateBidsBase(
                jooqDbSteps.bidsBaseSteps().getBidsBaseByBidId(autotargetingId2).setLastchange(TIMESTAMP_1_MINUTE_AGO)
        );
        jooqDbSteps.bidsSteps().updateBids(
                jooqDbSteps.bidsSteps().getBidById(keywordId1).setModtime(TIMESTAMP_3_MINUTES_AGO)
        );
        jooqDbSteps.bidsSteps().updateBids(
                jooqDbSteps.bidsSteps().getBidById(keywordId2).setModtime(TIMESTAMP_1_MINUTE_AGO)
        );
    }

    @Test
    public void getWithModifiedSinceByKeywordIds() {
        GetResponse getResponse = api.userSteps.keywordsSteps().keywordsGetRawResponse(
                new GetRequestMap()
                        .withFieldNames(KeywordFieldEnum.ID)
                        .withSelectionCriteria(new KeywordsSelectionCriteriaMap()
                                .withIds(keywordId1, keywordId2, autotargetingId1, autotargetingId2)
                                .withModifiedSince(modifiedSince.toString())
                        )
        );
        assertThat("вернулся правильный ответ", getResponse.getKeywords(), matcher);
    }

    @Test
    public void getWithModifiedSinceByAdGroupId() {
        GetResponse getResponse = api.userSteps.keywordsSteps().keywordsGetRawResponse(
                new GetRequestMap()
                        .withFieldNames(KeywordFieldEnum.ID)
                        .withSelectionCriteria(new KeywordsSelectionCriteriaMap()
                                .withAdGroupIds(adGroupId, adGroupId2)
                                .withModifiedSince(modifiedSince.toString())
                        )
        );
        assertThat("вернулся правильный ответ", getResponse.getKeywords(), matcher);
    }

    @Test
    public void getWithModifiedSinceByCampaignId() {
        GetResponse getResponse = api.userSteps.keywordsSteps().keywordsGetRawResponse(
                new GetRequestMap()
                        .withFieldNames(KeywordFieldEnum.ID)
                        .withSelectionCriteria(new KeywordsSelectionCriteriaMap()
                                .withCampaignIds(campaignId)
                                .withModifiedSince(modifiedSince.toString())
                        )
        );
        assertThat("вернулся правильный ответ", getResponse.getKeywords(), matcher);
    }
}
