package ru.yandex.autotests.directapi.model.api5.reports;

import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

import com.yandex.direct.api.v5.general.AttributionModelEnum;
import com.yandex.direct.api.v5.general.CurrencyEnum;
import com.yandex.direct.api.v5.general.YesNoEnum;
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.FormatEnum;
import com.yandex.direct.api.v5.reports.Page;
import com.yandex.direct.api.v5.reports.ReportDefinition;
import com.yandex.direct.api.v5.reports.ReportTypeEnum;
import com.yandex.direct.api.v5.reports.SelectionCriteria;
import org.joda.time.DateTime;

import ru.yandex.autotests.direct.utils.converter.BeanMapToBeanConverter;
import ru.yandex.autotests.direct.utils.model.ModelBeanMap;

import static ch.lambdaj.Lambda.convert;
import static ru.yandex.autotests.directapi.utils.CallerUtils.getCallerClassAndMethodNames;

/**
 * Created by pavryabov on 31.05.16.
 */
public class ReportDefinitionMap extends ModelBeanMap<ReportDefinitionMap> {

    public static final String SELECTION_CRITERIA = "selectionCriteria";
    public static final String GOALS = "goals";
    public static final String ATTRIBUTION_MODELS = "attributionModels";
    public static final String FIELD_NAMES = "fieldNames";
    public static final String PAGE = "page";
    public static final String ORDER_BY = "orderBy";
    public static final String REPORT_NAME = "reportName";
    public static final String REPORT_TYPE = "reportType";
    public static final String DATE_RANGE_TYPE = "dateRangeType";
    public static final String FORMAT = "format";
    public static final String CURRENCY = "currency";
    public static final String INCLUDE_VAT = "includeVAT";
    public static final String INCLUDE_DISCOUNT = "includeDiscount";

    public static final String DEFAULT_REPORT_NAME = "TestReport";

    public ReportDefinitionMap() {
        super();
        setBean(new ReportDefinition());
    }

    public ReportDefinitionMap(ReportDefinition reportDefinition) {
        super();
        setBean(reportDefinition);
    }

    @Override
    public ReportDefinitionMap put(String fieldName, Object value) {
        super.put(fieldName, value);
        return this;
    }

    @Override
    public ReportDefinition getBean() {
        return (ReportDefinition) super.getBean();
    }

    public ReportDefinitionMap withSelectionCriteria(SelectionCriteriaMap selectionCriteriaMap) {
        SelectionCriteria selectionCriteria =
                ((selectionCriteriaMap == null) ? null : (SelectionCriteria) (selectionCriteriaMap.getBean()));
        this.put(SELECTION_CRITERIA, selectionCriteria);
        return this;
    }

    public ReportDefinitionMap withGoals(Long... goalIds) {
        this.put(GOALS, Arrays.stream(goalIds).map(Object::toString).collect(Collectors.toList()));
        return this;
    }

    public ReportDefinitionMap withAttributionModels(AttributionModelEnum... attributionModels) {
        this.put(ATTRIBUTION_MODELS, Arrays.asList(attributionModels));
        return this;
    }

    public ReportDefinitionMap withFieldNames(FieldEnum... fieldNames) {
        this.put(FIELD_NAMES, Arrays.asList(fieldNames));
        return this;
    }

    public ReportDefinitionMap withPage(PageMap pageMap) {
        Page page = ((pageMap == null) ? null : (Page) (pageMap.getBean()));
        this.put(PAGE, page);
        return this;
    }

    public ReportDefinitionMap withOrderBy(OrderByMap... orderBy) {
        this.put(ORDER_BY, (orderBy == null) ? null : convert(orderBy, new BeanMapToBeanConverter<>()));
        return this;
    }

    public ReportDefinitionMap withReportName(String reportName) {
        this.put(REPORT_NAME, reportName);
        return this;
    }

    public ReportDefinitionMap withUniqueReportName() {
        return withReportName(
                DEFAULT_REPORT_NAME + ' ' + getCallerClassAndMethodNames() + ' ' + UUID.randomUUID().toString());
    }

    public ReportDefinitionMap withReportType(ReportTypeEnum reportType) {
        this.put(REPORT_TYPE, reportType);
        return this;
    }

    public ReportDefinitionMap withDateRangeType(DateRangeTypeEnum dateRangeType) {
        this.put(DATE_RANGE_TYPE, dateRangeType);
        return this;
    }

    public ReportDefinitionMap withFormat(FormatEnum format) {
        this.put(FORMAT, format);
        return this;
    }

    public ReportDefinitionMap withCurrency(CurrencyEnum currency) {
        this.put(CURRENCY, currency);
        return this;
    }

    public ReportDefinitionMap withIncludeVAT(YesNoEnum includeVAT) {
        this.put(INCLUDE_VAT, includeVAT);
        return this;
    }

    public ReportDefinitionMap withIncludeDiscount(YesNoEnum includeDiscount) {
        this.put(INCLUDE_DISCOUNT, includeDiscount);
        return this;
    }

    public List<FieldEnum> getFieldNames() {

        return getBean().getFieldNames();
    }

    public String getReportName() {
        return getBean().getReportName();
    }

    public ReportDefinitionMap withDefaultCustomReportWithUniqueReportName() {
        return this.withDefaultReportWithTypeAndUniqueReportName(ReportTypeEnum.CUSTOM_REPORT);
    }

    public ReportDefinitionMap withDefaultReportWithTypeAndUniqueReportName(ReportTypeEnum reportType) {
        return this
                .withDefaultReportWithType(reportType)
                .withUniqueReportName();
    }

    public ReportDefinitionMap withDefaultCustomReport() {
        return this.withDefaultReportWithType(ReportTypeEnum.CUSTOM_REPORT);
    }

    public ReportDefinitionMap withDefaultReportWithType(ReportTypeEnum reportType) {
        return this
                .withFieldNames(FieldEnum.CAMPAIGN_ID)
                .withReportType(reportType)
                .withDateRangeType(DateRangeTypeEnum.LAST_MONTH)
                .withFormat(FormatEnum.TSV)
                .withIncludeVAT(YesNoEnum.YES)
                .withIncludeDiscount(YesNoEnum.NO)
                .withPage(new PageMap().withLimit(1L));
    }

    public ReportDefinitionMap withCustomDates(String dateFrom, String dateTo) {
        return this
                .withDateRangeType(DateRangeTypeEnum.CUSTOM_DATE)
                .withSelectionCriteria(
                        new SelectionCriteriaMap()
                                .withDateFrom(dateFrom)
                                .withDateTo(dateTo)
                );
    }

    public ReportDefinitionMap withCustomDates(DateTime dateFrom, DateTime dateTo) {
        return withCustomDates(dateFrom.toString(ReportsData.DATE_FORMAT), dateTo.toString(ReportsData.DATE_FORMAT));
    }

    public ReportDefinitionMap withCustomDatesAndCampaignIds(String dateFrom, String dateTo, Long... campaignIds) {
        return this
                .withDateRangeType(DateRangeTypeEnum.CUSTOM_DATE)
                .withSelectionCriteria(
                        new SelectionCriteriaMap()
                                .withDateFrom(dateFrom)
                                .withDateTo(dateTo)
                                .withFilter(getFilterByCampaignIds(campaignIds))
                );
    }

    public ReportDefinitionMap withCustomDatesAndCampaignIds(DateTime dateFrom, DateTime dateTo, Long... campaignIds) {
        return withCustomDatesAndCampaignIds(dateFrom.toString(ReportsData.DATE_FORMAT),
                dateTo.toString(ReportsData.DATE_FORMAT), campaignIds);
    }

    public ReportDefinitionMap withCampaignIds(Long... campaignIds) {
        return this
                .withSelectionCriteria(
                        new SelectionCriteriaMap().withFilter(getFilterByCampaignIds(campaignIds))
                );
    }

    private FilterItemMap getFilterByCampaignIds(Long... campaignIds) {
        return new FilterItemMap()
                .withField(FieldEnum.CAMPAIGN_ID)
                .withOperator(FilterOperatorEnum.IN)
                .withValues(campaignIds);
    }

    public ReportDefinitionMap withDefaultSearchQueryReportWithUniqueReportName() {
        return this
                .withFieldNames(FieldEnum.CAMPAIGN_ID)
                .withUniqueReportName()
                .withReportType(ReportTypeEnum.SEARCH_QUERY_PERFORMANCE_REPORT)
                .withDateRangeType(DateRangeTypeEnum.LAST_MONTH)
                .withFormat(FormatEnum.TSV)
                .withIncludeVAT(YesNoEnum.YES)
                .withIncludeDiscount(YesNoEnum.NO)
                .withPage(new PageMap().withLimit(1L));
    }

    public ReportDefinitionMap withDefaultLimitedPeriod() {
        return this
                .withSelectionCriteria(new SelectionCriteriaMap().withDefaultLimitedPeriod())
                .withDateRangeType(DateRangeTypeEnum.CUSTOM_DATE);
    }
}
