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

import java.util.ArrayList;
import java.util.List;

import com.yandex.direct.api.v5.general.ExceptionNotification;
import org.hamcrest.Matcher;

import ru.yandex.autotests.direct.utils.config.DirectTestRunProperties;
import ru.yandex.autotests.direct.utils.matchers.BeanCompareStrategy;
import ru.yandex.autotests.direct.utils.matchers.BeanEquals;

import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.emptyIterable;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;

/**
 * Created by chicos on 17.07.15.
 */
public class MultiIdsExpectedResult extends MultiIdsActionResultMap {

    public MultiIdsExpectedResult() {
        super();
    }

    private BeanCompareStrategy resultCompareStrategy;

    public static MultiIdsExpectedResult success() {
        return success(notNullValue());
    }

    public static MultiIdsExpectedResult success(Long id) {
        return success(equalTo(id));
    }

    private static MultiIdsExpectedResult success(Matcher idMatcher) {
        MultiIdsExpectedResult map = new MultiIdsExpectedResult();
        map.resultCompareStrategy = new BeanCompareStrategy()
                .putFieldMatcher(IDS, idMatcher)
                .putFieldMatcher(WARNINGS, emptyIterable())
                .putFieldMatcher(ERRORS, emptyIterable());
        return map;
    }

    public static MultiIdsExpectedResult warnings(Long id, ExceptionNotificationMap... warnings) {
        return warnings(equalTo(id), warnings);
    }

    public static MultiIdsExpectedResult warnings(ExceptionNotificationMap... warnings) {
        return warnings(notNullValue(), warnings);
    }

    private static MultiIdsExpectedResult warnings(Matcher idMatcher, ExceptionNotificationMap... warnings) {
        MultiIdsExpectedResult map = new MultiIdsExpectedResult();
        List<BeanEquals> expectedWarningMatchers = new ArrayList<>();

        //replace details matcher to ignore code in messages like '#82518511 Warning message detail here'
        for (ExceptionNotificationMap warning : warnings) {
            BeanCompareStrategy strategy = new BeanCompareStrategy();
            if (((ExceptionNotification) warning.getBean()).getDetails() == null) {
                strategy.putFieldMatcher(ExceptionNotificationMap.DETAILS, nullValue());
            }
            BeanEquals warningMatcher = BeanEquals.beanEquals(warning.getBean()).accordingStrategy(strategy);

            //ignore message and details if ignore code set in properties
            if (DirectTestRunProperties.getInstance().getDirectApiIgnoreDetailForCodes() != null &&
                    DirectTestRunProperties.getInstance().getDirectApiIgnoreDetailForCodes()
                            .contains(String.valueOf(((ExceptionNotification) warning.getBean()).getCode())))
            {
                warningMatcher.byFields(ExceptionNotificationMap.CODE);
            }
            expectedWarningMatchers.add(warningMatcher);
        }

        BeanEquals[] array = new BeanEquals[expectedWarningMatchers.size()];
        map.resultCompareStrategy = new BeanCompareStrategy()
                .putFieldMatcher(IDS, idMatcher)
                .putFieldMatcher(WARNINGS, containsInAnyOrder(expectedWarningMatchers.toArray(array)))
                .putFieldMatcher(ERRORS, emptyIterable());
        map.withWarnings(warnings);
        return map;
    }

    public static MultiIdsExpectedResult errors(ExceptionNotificationMap... errors) {
        MultiIdsExpectedResult map = new MultiIdsExpectedResult();
        List<BeanEquals> expectedErrorMatchers = new ArrayList<>();

        //replace details matcher to ignore code in messages like '#82518511 Error message detail here'
        for (ExceptionNotificationMap error : errors) {
            BeanCompareStrategy strategy = new BeanCompareStrategy();
            if (((ExceptionNotification) error.getBean()).getDetails() == null) {
                strategy.putFieldMatcher(ExceptionNotificationMap.DETAILS, nullValue());
            }

            BeanEquals errorMatcher = BeanEquals.beanEquals(error.getBean()).accordingStrategy(strategy);
            //ignore message and details if ignore code set in properties
            if (DirectTestRunProperties.getInstance().getDirectApiIgnoreDetailForCodes() != null &&
                    DirectTestRunProperties.getInstance().getDirectApiIgnoreDetailForCodes()
                            .contains(String.valueOf(((ExceptionNotification) error.getBean()).getCode())))
            {
                errorMatcher.byFields(ExceptionNotificationMap.CODE);
            }
            expectedErrorMatchers.add(errorMatcher);
        }

        BeanEquals[] array = new BeanEquals[expectedErrorMatchers.size()];
        map.resultCompareStrategy = new BeanCompareStrategy()
                .putFieldMatcher(IDS, emptyIterable())
                .putFieldMatcher(WARNINGS, emptyIterable())
                .putFieldMatcher(ERRORS, containsInAnyOrder(expectedErrorMatchers.toArray(array)));
        map.withErrors(errors);
        return map;
    }

    public BeanCompareStrategy getActionResultCompareStrategy() {
        return resultCompareStrategy;
    }
}
