package ru.yandex.autotests.directapi.reports.criteriareport;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

import com.yandex.direct.api.v5.reports.DateRangeTypeEnum;
import com.yandex.direct.api.v5.reports.FieldEnum;
import com.yandex.direct.api.v5.reports.FilterOperatorEnum;
import com.yandex.direct.api.v5.reports.ReportTypeEnum;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.hamcrest.core.Every;
import org.junit.ClassRule;
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.directapi.darkside.Logins;
import ru.yandex.autotests.directapi.model.api5.reports.FilterItemMap;
import ru.yandex.autotests.directapi.model.api5.reports.PageMap;
import ru.yandex.autotests.directapi.model.api5.reports.ReportDefinitionMap;
import ru.yandex.autotests.directapi.model.api5.reports.ReportsData;
import ru.yandex.autotests.directapi.model.api5.reports.ReportsLine;
import ru.yandex.autotests.directapi.model.api5.reports.SelectionCriteriaMap;
import ru.yandex.autotests.directapi.reports.ReportsFeatures;
import ru.yandex.autotests.directapi.reports.ReportsLogins;
import ru.yandex.autotests.directapi.rules.ApiSteps;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Issue;

import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.not;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assumeThat;

/**
 * Created by andy-ilyin on 13.01.17.
 */
@Aqua.Test
@Description("CRITERIA_PERFORMANCE_REPORT: Filter, положительные сценарии")
@Issue("https://st.yandex-team.ru/TESTIRT-10893")
@Features(ReportsFeatures.CRITERIA_PERFORMANCE_REPORT)
@RunWith(Parameterized.class)
public class CriteriaPerformanceReportFilterPositiveTest {
    private static final Long[] CAMPAIGN_IDS = new Long[] { 37137827L, 37136117L };
    private static final long AD_GROUP_ID = 3860412970L;

    @ClassRule
    public static final ApiSteps api = new ApiSteps().as(Logins.LOGIN_SUPER).clientLogin(ReportsLogins.CLIENT_FOR_CRITERIA_PERFORMANCE_REPORT3);

    @Parameterized.Parameter
    public FieldEnum fieldName;

    @Parameterized.Parameter(1)
    public FieldEnum[] resultFieldNames;

    @Parameterized.Parameter(2)
    public FilterOperatorEnum operator;

    @Parameterized.Parameter(3)
    public String[] values;

    @Parameterized.Parameter(4)
    public Matcher<ReportsLine> rowMatcher;

    @Parameterized.Parameters(name="{0}")
    public static Collection<Object[]> parameters() {
        Object[][] result = new Object[][] {
                new Object[] {
                        FieldEnum.AD_GROUP_ID,
                        new FieldEnum[] { FieldEnum.AD_GROUP_ID },
                        FilterOperatorEnum.EQUALS,
                        new String[] { Long.valueOf(AD_GROUP_ID).toString() },
                        hasProperty("adGroupId", equalTo(AD_GROUP_ID)),
                },
                new Object[] {
                        FieldEnum.AD_NETWORK_TYPE,
                        new FieldEnum[] { FieldEnum.AD_NETWORK_TYPE },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "SEARCH" },
                        hasProperty("adNetworkType", equalTo("SEARCH")),
                },
                new Object[] {
                        FieldEnum.AGE,
                        new FieldEnum[] { FieldEnum.AGE },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "AGE_18_24" },
                        hasProperty("age", equalTo("AGE_18_24")),
                },
                // TODO не работает в приложении, починить, когда заработает
//                new Object[] {
//                        FieldEnum.AUDIENCE_TARGET_ID,
//                        new FieldEnum[0],
//                        FilterOperatorEnum.EQUALS,
//                        new String[] { "15" },
//                        hasProperty("audienceTargetId", equalTo(15)),
//                },
                new Object[] {
                        FieldEnum.AVG_CLICK_POSITION,
                        new FieldEnum[] { FieldEnum.AVG_CLICK_POSITION },
                        FilterOperatorEnum.GREATER_THAN,
                        new String[] { "2" },
                        hasProperty("avgClickPosition", greaterThan(BigDecimal.valueOf(2.0))),
                },
                new Object[] {
                        FieldEnum.AVG_CPC,
                        new FieldEnum[] { FieldEnum.AVG_CPC },
                        FilterOperatorEnum.GREATER_THAN,
                        new String[] { "1500000" },
                        hasProperty("avgCpc", greaterThan(BigDecimal.valueOf(1500000))),
                },
                new Object[] {
                        FieldEnum.AVG_IMPRESSION_POSITION,
                        new FieldEnum[] { FieldEnum.AVG_IMPRESSION_POSITION },
                        FilterOperatorEnum.GREATER_THAN,
                        new String[] { "0" },
                        hasProperty("avgImpressionPosition", greaterThan(BigDecimal.valueOf(0))),
                },
                new Object[] {
                        FieldEnum.AVG_PAGEVIEWS,
                        new FieldEnum[] { FieldEnum.AVG_PAGEVIEWS },
                        FilterOperatorEnum.GREATER_THAN,
                        new String[] { "40" },
                        hasProperty("avgPageviews", greaterThan(BigDecimal.valueOf(40))),
                },
                new Object[] {
                        FieldEnum.BOUNCE_RATE,
                        new FieldEnum[] { FieldEnum.BOUNCE_RATE },
                        FilterOperatorEnum.GREATER_THAN,
                        new String[] { "10" },
                        hasProperty("bounceRate", greaterThan(BigDecimal.valueOf(10))),
                },
                new Object[] {
                        FieldEnum.CAMPAIGN_ID,
                        new FieldEnum[] { FieldEnum.CAMPAIGN_ID },
                        FilterOperatorEnum.IN,
                        Arrays.stream(CAMPAIGN_IDS)
                                .map(Object::toString)
                                .collect(Collectors.toList())
                                .toArray(new String[0]),
                        hasProperty("campaignId", anyOf(Arrays.stream(CAMPAIGN_IDS).
                                map(Matchers::equalTo).
                                collect(Collectors.toList()))),
                },
                new Object[] {
                        FieldEnum.CARRIER_TYPE,
                        new FieldEnum[] { FieldEnum.CARRIER_TYPE },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "STATIONARY" },
                        hasProperty("carrierType", equalTo("STATIONARY")),
                },
                new Object[] {
                        FieldEnum.CLICK_TYPE,
                        new FieldEnum[] { FieldEnum.CLICK_TYPE },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "TITLE" },
                        hasProperty("clickType", equalTo("TITLE")),
                },
                new Object[] {
                        FieldEnum.CLICKS,
                        new FieldEnum[] { FieldEnum.CLICKS },
                        FilterOperatorEnum.GREATER_THAN,
                        new String[] { "1" },
                        hasProperty("clicks", greaterThan(1)),
                },
                new Object[] {
                        FieldEnum.CONVERSION_RATE,
                        new FieldEnum[] { FieldEnum.CONVERSION_RATE },
                        FilterOperatorEnum.GREATER_THAN,
                        new String[] { "0.5" },
                        hasProperty("conversionRate", greaterThan(BigDecimal.valueOf(0.5))),
                },
                new Object[] {
                        FieldEnum.CONVERSIONS,
                        new FieldEnum[] { FieldEnum.CONVERSIONS },
                        FilterOperatorEnum.GREATER_THAN,
                        new String[] { "1000" },
                        hasProperty("conversions", greaterThanOrEqualTo(1000)),
                },
                new Object[] {
                        FieldEnum.COST,
                        new FieldEnum[] { FieldEnum.COST },
                        FilterOperatorEnum.GREATER_THAN,
                        new String[] { "20000000" },
                        hasProperty("cost", greaterThan(BigDecimal.valueOf(20000000))),
                },
                new Object[] {
                        FieldEnum.COST_PER_CONVERSION,
                        new FieldEnum[] { FieldEnum.COST_PER_CONVERSION },
                        FilterOperatorEnum.GREATER_THAN,
                        new String[] { "100" },
                        hasProperty("costPerConversion", greaterThan(BigDecimal.valueOf(100))),
                },
                new Object[] {
                        FieldEnum.CRITERIA_TYPE,
                        new FieldEnum[] { FieldEnum.CRITERIA_TYPE },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "KEYWORD" },
                        hasProperty("criteriaType", equalTo("KEYWORD")),
                },
                new Object[] {
                        FieldEnum.CRITERION_TYPE,
                        new FieldEnum[] { FieldEnum.CRITERION_TYPE },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "KEYWORD" },
                        hasProperty("criterionType", equalTo("KEYWORD")),
                },
                new Object[] {
                        FieldEnum.CTR,
                        new FieldEnum[] { FieldEnum.CTR },
                        FilterOperatorEnum.GREATER_THAN,
                        new String[] { "5" },
                        hasProperty("ctr", greaterThan(BigDecimal.valueOf(5))),
                },
                new Object[] {
                        FieldEnum.DEVICE,
                        new FieldEnum[] { FieldEnum.DEVICE },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "DESKTOP" },
                        hasProperty("device", equalTo("DESKTOP")),
                },
                new Object[] {
                        FieldEnum.EXTERNAL_NETWORK_NAME,
                        new FieldEnum[] { FieldEnum.EXTERNAL_NETWORK_NAME },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "Yandex and YAN" },
                        hasProperty("externalNetworkName", equalTo("Yandex and YAN")),
                },
                new Object[] {
                        FieldEnum.GENDER,
                        new FieldEnum[] { FieldEnum.GENDER },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "GENDER_MALE" },
                        hasProperty("gender", equalTo("GENDER_MALE")),
                },
                new Object[] {
                        FieldEnum.GOALS_ROI,
                        new FieldEnum[] { FieldEnum.GOALS_ROI },
                        FilterOperatorEnum.GREATER_THAN,
                        new String[] { "1000" },
                        hasProperty("goalsRoi", greaterThan(BigDecimal.valueOf(1000))),
                },
                new Object[] {
                        FieldEnum.IMPRESSIONS,
                        new FieldEnum[] { FieldEnum.IMPRESSIONS },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "15" },
                        hasProperty("impressions", equalTo(15)),
                },
                new Object[] {
                        FieldEnum.KEYWORD,
                        new FieldEnum[] { FieldEnum.CRITERION_ID },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "икеа ~0" },
                        hasProperty("criterionId", equalTo(17118387027L)),
                },
                new Object[] {
                        FieldEnum.LOCATION_OF_PRESENCE_ID,
                        new FieldEnum[] { FieldEnum.LOCATION_OF_PRESENCE_ID },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "15" },
                        hasProperty("locationOfPresenceId", equalTo(15)),
                },
                new Object[] {
                        FieldEnum.MOBILE_PLATFORM,
                        new FieldEnum[] { FieldEnum.MOBILE_PLATFORM },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "IOS" },
                        hasProperty("mobilePlatform", equalTo("IOS")),
                },
                new Object[] {
                        FieldEnum.PLACEMENT,
                        new FieldEnum[] { FieldEnum.PLACEMENT },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "yandex.ru" },
                        hasProperty("placement", containsString("yandex.ru")),
                },
                new Object[] {
                        FieldEnum.PROFIT,
                        new FieldEnum[] { FieldEnum.PROFIT },
                        FilterOperatorEnum.GREATER_THAN,
                        new String[] { "-15000000" },
                        hasProperty("profit", greaterThan(BigDecimal.valueOf(-15000000))),
                },
                new Object[] {
                        FieldEnum.REVENUE,
                        new FieldEnum[] { FieldEnum.REVENUE },
                        FilterOperatorEnum.GREATER_THAN,
                        new String[] { "95390000000" },
                        hasProperty("revenue", greaterThan(BigDecimal.valueOf(7000000000L))),
                },
                new Object[] {
                        FieldEnum.SLOT,
                        new FieldEnum[] { FieldEnum.SLOT },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "PREMIUMBLOCK" },
                        hasProperty("slot", equalTo("PREMIUMBLOCK")),
                },
                new Object[] {
                        FieldEnum.TARGETING_LOCATION_ID,
                        new FieldEnum[] { FieldEnum.TARGETING_LOCATION_ID },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "10715" },
                        hasProperty("targetingLocationId", equalTo(10715)),
                },
                new Object[] {
                        FieldEnum.TARGETING_CATEGORY,
                        new FieldEnum[] { FieldEnum.TARGETING_CATEGORY },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "UNKNOWN" },
                        hasProperty("targetingCategory", equalTo("UNKNOWN")),
                },
                new Object[] {
                        FieldEnum.INCOME_GRADE,
                        new FieldEnum[] { FieldEnum.INCOME_GRADE },
                        FilterOperatorEnum.EQUALS,
                        new String[] { "OTHER" },
                        hasProperty("incomeGrade", equalTo("OTHER")),
                },
        };

        return Arrays.asList(result);
    }

    @Test
    public void test() {
        List<FieldEnum> fieldNames = new LinkedList<>(Arrays.asList(resultFieldNames));
        fieldNames.add(0, FieldEnum.DATE);

        if (!fieldNames.contains(FieldEnum.CRITERIA_TYPE) && !fieldNames.contains(FieldEnum.CRITERION_TYPE)) {
            fieldNames.add(FieldEnum.CRITERION_TYPE);
        }

        if (!fieldNames.contains(FieldEnum.CRITERION_ID)) {
            fieldNames.add(FieldEnum.CRITERION_ID);
        }

        List<FilterItemMap> filters = new LinkedList<>(Collections.singletonList(new FilterItemMap()
                .withField(fieldName)
                .withOperator(operator)
                .withValues(values)));

        if (fieldName != FieldEnum.CAMPAIGN_ID) {
            filters.add(new FilterItemMap()
                    .withField(FieldEnum.CAMPAIGN_ID)
                    .withOperator(FilterOperatorEnum.IN)
                    .withValues(CAMPAIGN_IDS));
        }

        ReportsData report = api.userSteps.reportsSteps().callReportsXml(new ReportDefinitionMap()
                .withDefaultReportWithTypeAndUniqueReportName(ReportTypeEnum.CRITERIA_PERFORMANCE_REPORT)
                .withDateRangeType(DateRangeTypeEnum.CUSTOM_DATE)
                .withSelectionCriteria(new SelectionCriteriaMap()
                        .withDateFrom("2021-03-17")
                        .withDateTo("2021-03-23")
                        .withFilter(filters.toArray(new FilterItemMap[0])))
                .withFieldNames(fieldNames.toArray(new FieldEnum[0]))
                .withPage(new PageMap().withLimit(1500L)));

        assumeThat("отчёт не пустой", report.getReportsLines(), not(empty()));

        assertThat("все строки соответствуют фильтру",
                report.getReportsLines(), Every.everyItem(rowMatcher));
    }
}
