package ru.yandex.autotests.directapi.steps.campaigns;

import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;

import com.jayway.jsonpath.Criteria;
import com.jayway.jsonpath.Filter;
import com.jayway.jsonpath.JsonPath;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.hamcrest.Matcher;

import ru.yandex.autotests.direct.db.steps.DirectJooqDbSteps;
import ru.yandex.autotests.direct.utils.ReflectionUtils;
import ru.yandex.autotests.direct.utils.matchers.BeanCompareStrategy;
import ru.yandex.autotests.direct.utils.matchers.BeanEquals;
import ru.yandex.autotests.direct.utils.money.Currency;
import ru.yandex.autotests.direct.utils.money.Money;
import ru.yandex.autotests.directapi.apiclient.RequestHeader;
import ru.yandex.autotests.directapi.apiclient.config.ConnectionConfig;
import ru.yandex.autotests.directapi.apiclient.errors.AxisError;
import ru.yandex.autotests.directapi.apiclient.methods.Method;
import ru.yandex.autotests.directapi.darkside.steps.DarkSideSteps;
import ru.yandex.autotests.directapi.exceptions.DirectAPIException;
import ru.yandex.autotests.directapi.model.campaigns.CampaignIDInfoMap;
import ru.yandex.autotests.directapi.model.campaigns.CampaignIDsInfoMap;
import ru.yandex.autotests.directapi.model.campaigns.CampaignInfoMap;
import ru.yandex.autotests.directapi.model.campaigns.GetCampaignsInfoMap;
import ru.yandex.autotests.directapi.model.campaigns.StrategyMap;
import ru.yandex.autotests.directapi.model.common.Value;
import ru.yandex.autotests.directapi.rules.Bin;
import ru.yandex.autotests.directapi.rules.Binable;
import ru.yandex.autotests.directapi.steps.BaseApiSteps;
import ru.yandex.autotests.directapi.steps.UserSteps;
import ru.yandex.autotests.irt.testutils.allure.LogSteps;
import ru.yandex.autotests.irt.testutils.allure.TestSteps;
import ru.yandex.autotests.irt.testutils.json.JsonUtils;
import ru.yandex.qatools.allure.annotations.Step;

import static org.apache.commons.lang3.StringUtils.uncapitalize;
import static org.hamcrest.CoreMatchers.equalTo;


/**
 * Created with IntelliJ IDEA.
 * User: mariabye
 * Date: 24.06.13
 * Time: 18:29
 * To change this template use File | Settings | File Templates.
 */
public class CampaignSteps extends BaseApiSteps implements Binable<Integer> {
    private LogSteps log = LogSteps.getLogger(this.getClass());
    private static CampaignSteps _instance;
    public StrategyMap strategyMap;
    public StrategyMap contextStrategyMap;
    public CampaignInfoMap campaignInfoMap;

    //region Preset campaigns for CPAOptimizer
    //  at-serv-cpa
    public static final int AVERAGE_CPA_SERV_CID1 = 7330454;
    public static final int AVERAGE_CPA_SERV_CID2 = 7330455;
    public static final int AVERAGE_CPA_SERV_CID3 = 7330462;
    public static final int AVERAGE_CPA_SERV_CID4 = 7330465;
    public static final int AVERAGE_CPA_SERV_CID5 = 7330467;


    // at-direct-api-test
    // агентская
    public static final int AVERAGE_CPA_AGENCY_CID1 = 7273721;
    public static final int AVERAGE_CPA_AGENCY_CID2 = 7273728;
    public static final int AVERAGE_CPA_AGENCY_CID3 = 7330479;
    public static final int AVERAGE_CPA_AGENCY_CID4 = 7330482;

    //самостоятельная
    public static final int AVERAGE_CPA_SELF_CID1 = 7273740;
    public static final int AVERAGE_CPA_SELF_CID2 = 7273762;

    // сервис
    public static final int AVERAGE_CPA_SERV_API_TEST_CID = 2991372;
    //endregion
    public Bin<Integer> bin = new Bin<>(this);

    private CampaignSteps(ConnectionConfig connectionConfig, RequestHeader requestHeader) {
        super(connectionConfig, requestHeader);
    }

    public static CampaignSteps getInstance(ConnectionConfig connectionConfig, RequestHeader requestHeader) {
        if (_instance == null) {
            _instance = new CampaignSteps(connectionConfig, requestHeader);
        } else {
            _instance.setConnectionConfig(connectionConfig);
            _instance.setRequestHeader(requestHeader);
        }
        _instance.reloadModels();
        return _instance;

    }

    private void reloadModels() {
        String packageName = connectionConfig.getPackage();
        campaignInfoMap = new CampaignInfoMap(packageName);
        strategyMap = new StrategyMap(packageName, StrategyMap.StrategyType.SEARCH);
        if ((connectionConfig.getAPIVersion() == 104) || (connectionConfig.getAPIVersion() == 2) || (
                connectionConfig.getAPIVersion() == 12))
        {
            contextStrategyMap = new StrategyMap(packageName, StrategyMap.StrategyType.CONTEXT);
        }
    }

    public Callable clearBin(final Set<Integer> binData) {
        return () -> {
            Integer[] campaignIDs = binData.toArray(new Integer[0]);

            DarkSideSteps darkSideSteps = getDarkSideSteps();
            // DIRECT-134337: недоудаляются кампании на ТС
            // тут был вызов getDarkSideSteps().getCampaignFakeSteps().makeCampaignReadyForDelete(binData.keySet())
            // этот он иногда не работает, поэтому действуем более хардкорно

            DirectJooqDbSteps jooqDbSteps = darkSideSteps.getDirectJooqDbSteps();
            for (Integer campaignID : campaignIDs) {
                try {
                    int shard = jooqDbSteps.shardingSteps().getShardByCid(campaignID);
                    jooqDbSteps.useShard(shard).campaignsSteps().makeCampaignReadyForDelete(campaignID.longValue(), false);
                    try {
                        jooqDbSteps.useShard(shard).bsResyncQueueSteps()
                                .deleteCampaignFromBsResyncQueueByCid(campaignID.longValue());
                        jooqDbSteps.bsExportQueueSteps().deleteBsExportQueue(campaignID.longValue());
                    } catch (Exception e) {
                        log.info("TRASHER: ошибка удаления кампании: ошибка при удалении из очередей", e);
                    }
                } catch (Exception e) {
                    log.info("TRASHER: ошибка при подготовке к удалению кампании", e);
                }
            }


            for (Integer campaignID : campaignIDs) {
                try {
                    deleteCampaign(campaignID);
                } catch (Exception e) {
                    log.info("TRASHER: ошибка удаления кампании. " + e);
                }
            }

            return null;
        };
    }

    public void removeCampaignFromQueue(int campaignID) {
        log.info("Удаляем кампанию из очереди TRASHER-а");
        bin.removeFromBin(campaignID);
    }

    public void putCampaingToQueue(int campaignID) {
        log.info("Добавляем кампанию в очередь на удаление");
        bin.throwToBin(campaignID);
    }

    //region CreateOrUpdateCampaign
    public Integer createOrUpdateCampaign(CampaignInfoMap campaignInfo) {
        return jsonClient().invokeMethod(Method.CREATE_OR_UPDATE_CAMPAIGN, campaignInfo.getBean());
    }

    @Step("[CreateOrUpdateCampaign]: Создать кампанию")
    public int createCampaign(CampaignInfoMap campaignInfo) {
        int campaignID = createOrUpdateCampaign(campaignInfo);

        bin.throwToBin(campaignID);

        log.info("Кампания создана: campaignID = " + campaignID);
        return campaignID;
    }

    public int createDefaultCampaign() {
        return createDefaultCampaign(jsonClient().login());
    }

    @Step("Создать случайную кампанию для {0}")
    public int createDefaultCampaign(String login) {
        return createCampaign(campaignInfoMap.defaultCampaign().withLogin(login));
    }

    @Step("Создать {1} кампан(юю)ий для {0}")
    public int[] createDefaultCampaign(String login, int campaignCount) {
        int[] result = new int[]{};
        for (int i = 0; i < campaignCount; i++) {
            int campaignId = createDefaultCampaign(login);
            result = ArrayUtils.add(result, campaignId);
        }
        return result;
    }

    @Step("Создать случайную кампанию для {0} со стратегией на поиске {1}")
    public int createDefaultCampaignWithStrategy(String login, StrategyMap searchStrategy) {
        return createCampaign(campaignInfoMap
                .defaultCampaign()
                .withLogin(login)
                .withStrategy(searchStrategy));
    }

    public int createDefaultCampaignWithStrategy(StrategyMap searchStrategy) {
        return createDefaultCampaignWithStrategy(jsonClient().login(), searchStrategy);
    }

    @Step("Создать случайную кампанию для {0} со стратегией на поиске {1} и на тематике {2}")
    public int createDefaultCampaignWithStrategyAndContextStrategy(
            String login, StrategyMap searchStrategy, StrategyMap contextStrategy)
    {
        return createCampaign(campaignInfoMap
                .defaultCampaign()
                .withLogin(login)
                .withStrategy(searchStrategy)
                .withContextStrategy(contextStrategy));
    }

    public int createDefaultCampaignWithStrategyAndContextStrategy(
            StrategyMap searchStrategy, StrategyMap contextStrategy)
    {
        return createDefaultCampaignWithStrategyAndContextStrategy(
                jsonClient().login(),
                searchStrategy,
                contextStrategy
        );
    }

    public void setCampaignStrategy(int campaignID, StrategyMap strategy, StrategyMap contextStrategy) {
        setCampaignStrategy(campaignID, strategy, contextStrategy, null);
    }

    public void setCampaignStrategy(int campaignID,
            StrategyMap strategy,
            StrategyMap contextStrategy,
            Currency currency)
    {
        Object campaignInfo = getCampaignParams(campaignID);
        CampaignInfoMap campaignInfoMap = new CampaignInfoMap<>(campaignInfo)
                .withStrategy(strategy)
                .withContextStrategy(contextStrategy);
        if (currency != null) {
            campaignInfoMap.withCurrency(currency);
        }
        updateCampaign(campaignInfoMap);
    }

    public void setManualOnSearchStrategy(int campaignID) {
        setCampaignStrategy(campaignID,
                strategyMap.highestPosition(),
                contextStrategyMap.defaultStrategy());
    }

    public void setMaximumCoverageSrategy(int campaignID) {
        setCampaignStrategy(campaignID,
                strategyMap.rightBlockHighest(),
                contextStrategyMap.maximumCoverage());
    }

    public void setAutobudgetOnContextStrategy(int campaignID) {
        setCampaignStrategy(campaignID,
                strategyMap.showsDisabled(),
                contextStrategyMap.averageClickPrice());
    }

    public void setAutobudgetOnSearchStrategy(int campaignID) {
        setCampaignStrategy(campaignID,
                strategyMap.averageClickPrice(),
                contextStrategyMap.defaultStrategy());
    }

    public void setShowsDisabledOnContextStrategy(int campaignID) {
        setCampaignStrategy(campaignID,
                strategyMap.highestPosition(),
                contextStrategyMap.showsDisabled());
    }


    @Step("[CreateOrUpdateCampaign]: Сохранить кампанию")
    public void updateCampaign(CampaignInfoMap campaignInfo) {
        log.info(CampaignInfoMap.CAMPAIGN_ID + ": " + campaignInfo.get(CampaignInfoMap.CAMPAIGN_ID));
        createOrUpdateCampaign(campaignInfo);
        log.info("Кампания успешно сохранена");
    }
    //endregion

    //region GetCampaign(s)Params
    @Step("[GetCampaignParams]: campaignIDInfo = {0}")
    public <T> T getCampaignParams(CampaignIDInfoMap campaignIDInfo) {
        return (T) defaultClient().invokeMethod(Method.GET_CAMPAIGN_PARAMS, campaignIDInfo.getBean());
    }

    @Step("[GetCampaignParams]: campaignID = {0}")
    public <T> T getCampaignParams(int campaignID) {
        return getCampaignParams(new CampaignIDInfoMap(connectionConfig.getPackage())
                .withCampaignID(campaignID));
    }

    @Step("[GetCampaignParams]: currency = {0}, campaignID = {1}")
    @Deprecated
    public <T> T getCampaignParams(String currency, int campaignID) {
        return getCampaignParams(
                new CampaignIDInfoMap(connectionConfig.getPackage())
                        .withCampaignID(campaignID)
                        .withCurrency(currency));
    }

    @Step("[GetCampaignParams]: campaignID = {0}, currency = {1}, ")
    public <T> T getCampaignParams(int campaignID, Currency currency) {
        return getCampaignParams(
                new CampaignIDInfoMap(connectionConfig.getPackage())
                        .withCampaignID(campaignID)
                        .withCurrency(currency));
    }

    @Step("[GetCampaignsParams]: campaignIDsInfo = {0}")
    public <T> T getCampaignsParams(CampaignIDsInfoMap campaignIDsInfo) {
        return (T) jsonClient().invokeMethod(Method.GET_CAMPAIGNS_PARAMS, campaignIDsInfo.getBean());
    }

    @Step("[GetCampaignsParams]: campaignIDs = {0}")
    public <T> T[] getCampaignsParams(int... campaignIDs) {
        CampaignIDsInfoMap campaignIDsInfoMap =
                new CampaignIDsInfoMap(connectionConfig.getPackage()).withCampaignIDs(campaignIDs);
        return getCampaignsParams(campaignIDsInfoMap);
    }

    @Step("[GetCampaignParams]: currency = {0}, campaignID = {1}")
    public <CampaignInfo> CampaignInfo[] getCampaignsParams(String currency, int... campaignIDs) {
        CampaignIDsInfoMap campaignIDsInfoMap = new CampaignIDsInfoMap(connectionConfig.getPackage())
                .withCurrency((String) currency)
                .withCampaignIDs(campaignIDs);
        return getCampaignsParams(campaignIDsInfoMap);
    }

    public <CampaignInfo> CampaignInfo getCampaignsParams(int campaignID, Currency currency) {
        CampaignIDsInfoMap campaignIDsInfoMap = new CampaignIDsInfoMap(connectionConfig.getPackage())
                .withCurrency(currency)
                .withCampaignIDs(campaignID);
        CampaignInfo[] campaignInfos = getCampaignsParams(campaignIDsInfoMap);
        return campaignInfos[0];
    }

    public <T> T[] getCampaignsParams(String login) {
        CampaignIDsInfoMap campaignIDsInfoMap =
                new CampaignIDsInfoMap(connectionConfig.getPackage())
                        .withCampaignIDs(getCampaignIDs(login));
        return getCampaignsParams(campaignIDsInfoMap);
    }


    /**
     * Returns CampaignInfo list containing only active campaigns
     *
     * @param login
     * @param <T>
     * @return
     */
    public <T> List<T> getActiveCampaigns(String login) {
        List<T> activeCampaigns = new ArrayList();
        T[] campaigns = getCampaignsList(login);
        String isActive;
        for (T campaign : campaigns) {
            isActive =
                    (String) ReflectionUtils.invokeGetter(campaign, StringUtils.capitalize(CampaignInfoMap.IS_ACTIVE));
            if (isActive != null & isActive.equals(Value.YES)) {
                activeCampaigns.add(campaign);
            }

        }
        return activeCampaigns;
    }

    /**
     * Returns CampaignInfo list containing only moderated campaigns
     *
     * @param login
     * @param <T>
     * @return
     */
    public <T> List<T> getModeratedCampaigns(String login) {
        List<T> moderatedCampaigns = new ArrayList();
        T[] campaigns = getCampaignsList(login);
        String statusModerate;
        for (T campaign : campaigns) {
            statusModerate =
                    (String) ReflectionUtils
                            .invokeGetter(campaign, StringUtils.capitalize(CampaignInfoMap.STATUS_MODERATE));
            if (statusModerate != null & statusModerate.equals(Value.YES)) {
                moderatedCampaigns.add(campaign);
            }

        }
        return moderatedCampaigns;
    }

    public void shouldGetErrorOnGetCampaignsParams(AxisError axisError, int... campaignIDs) {
        CampaignIDsInfoMap campaignIDsInfoMap =
                new CampaignIDsInfoMap(connectionConfig.getPackage()).withCampaignIDs(campaignIDs);
        shouldGetErrorOn(
                Method.GET_CAMPAIGNS_PARAMS,
                campaignIDsInfoMap,
                axisError);
    }


    public <T> Callable<Boolean> campaignSumChanged(final CampaignInfoMap campaign) {
        return campaignSumChanged(campaign, properties.isDirectUseRealNotifyOrder());
    }

    public <T> Callable<Boolean> campaignSumChanged(final CampaignInfoMap campaign,
            final boolean billingNotifications)
    {
        return new Callable<Boolean>() {
            public Boolean call() throws Exception {
                Float sum = (Float) campaign.get(uncapitalize(CampaignInfoMap.SUM));
                Integer campaignID = (Integer) campaign.get(uncapitalize(CampaignInfoMap.CAMPAIGN_ID));
                if (!billingNotifications) {
                    UserSteps.getInstance().balanceSteps().synchronizeWithBalance(campaignID);
                }
                log.info("Wait sum != " + sum);
                return !sum.equals(
                        new BeanMap(getCampaignParams(campaignID)).get(CampaignInfoMap.SUM));
            }
        };
    }

    public <T> Callable<Boolean> campaignSumChanged(final CampaignInfoMap campaign, final String currency) {
        return campaignSumChanged(campaign, currency, properties.isDirectUseRealNotifyOrder());
    }

    public <T> Callable<Boolean> campaignSumChanged(
            final CampaignInfoMap campaign, final String currency, final boolean billingNotifications)
    {
        return new Callable<Boolean>() {
            public Boolean call() throws Exception {
                Float sum = (Float) campaign.get(uncapitalize(CampaignInfoMap.SUM));
                Integer campaignID = (Integer) campaign.get(uncapitalize(CampaignInfoMap.CAMPAIGN_ID));
                if (!billingNotifications) {
                    UserSteps.getInstance().balanceSteps().synchronizeWithBalance(campaignID);
                }
                log.info("Wait sum != " + sum);
                return !sum.equals(
                        new BeanMap(
                                getCampaignParams(currency, campaignID)).get(CampaignInfoMap.SUM));
            }
        };
    }

    /**
     * Метод используется для новых кампаний, у которых не было денег
     *
     * @param campaignID
     * @param <T>
     * @return
     */
    public <T> Callable<Boolean> campaignSumChanged(final int campaignID) {
        return campaignSumChanged(campaignID, properties.isDirectUseRealNotifyOrder());
    }

    public <T> Callable<Boolean> campaignSumChanged(final int campaignID, final boolean billingNotifications) {
        return new Callable<Boolean>() {
            public Boolean call() throws Exception {
                if (!billingNotifications) {
                    UserSteps.getInstance().balanceSteps().synchronizeWithBalance(campaignID);
                }
                log.info("Wait sum > 0");
                return !Float.valueOf(0).equals(
                        new BeanMap(getCampaignParams(campaignID)).get(CampaignInfoMap.SUM));
            }
        };
    }

    public Callable<Boolean> campaignSumChangedOnSum(final CampaignInfoMap campaign, final float sum) {
        return campaignSumChangedOnSum(campaign, sum, properties.isDirectUseRealNotifyOrder());
    }

    /**
     * @param campaign
     * @param sum                  balance changed diff to wait
     * @param billingNotifications whether to wait billing notification or not
     * @return
     */
    public Callable<Boolean> campaignSumChangedOnSum(
            final CampaignInfoMap campaign, final float sum, final boolean billingNotifications)
    {
        return new Callable<Boolean>() {
            public Boolean call() throws Exception {
                Float sumBefore = (Float) campaign.get(uncapitalize(CampaignInfoMap.SUM));
                Integer campaignID = (Integer) campaign.get(uncapitalize(CampaignInfoMap.CAMPAIGN_ID));
                Float sumAfter =
                        (Float) new BeanMap(getCampaignParams(campaignID)).get(CampaignInfoMap.SUM);
                if (!billingNotifications) {
                    UserSteps.getInstance().balanceSteps().synchronizeWithBalance(campaignID);
                }
                //log.info(String.format("Expected sum = %s", String.valueOf(sumBefore + sum)));
                //log.info(String.format("Got sum = %s", sumAfter.toString()));
                return
                        Money.valueOf(sumAfter).add(-sumBefore).setScale(2, RoundingMode.HALF_UP).floatValue()
                                .equals(sum);
            }
        };
    }

    public Callable<Boolean> campaignSumChangedOnSum(
            final CampaignInfoMap campaign, final float sum, final String currency)
    {
        return campaignSumChangedOnSum(
                campaign, sum, currency, properties.isDirectUseRealNotifyOrder());
    }

    public Callable<Boolean> campaignSumChangedOnSum(
            final CampaignInfoMap campaign, final float sum, final String currency, final boolean billingNotifications)
    {
        return new Callable<Boolean>() {
            public Boolean call() throws Exception {
                Float sumBefore = (Float) campaign.get(uncapitalize(CampaignInfoMap.SUM));
                Integer campaignID = (Integer) campaign.get(uncapitalize(CampaignInfoMap.CAMPAIGN_ID));
                Float sumAfter = (Float) new BeanMap(
                        getCampaignParams(currency, campaignID)).get(CampaignInfoMap.SUM);
                if (!billingNotifications) {
                    UserSteps.getInstance().balanceSteps().synchronizeWithBalance(campaignID);
                }
                //log.info(String.format("Expected sum = %s", String.valueOf(sumBefore + sum)));
                //log.info(String.format("Got sum = %s", sumAfter.toString()));
                return
                        Money.valueOf(sumAfter).add(-sumBefore).setScale(2, RoundingMode.HALF_UP).floatValue()
                                .equals(sum);
            }
        };
    }

    public Callable<Boolean> campaignSumChangedOnSum(CampaignInfoMap campaign, float sum, Currency currency) {
        return campaignSumChangedOnSum(campaign, sum, currency, properties.isDirectUseRealNotifyOrder());
    }

    public Callable<Boolean> campaignSumChangedOnSum(
            CampaignInfoMap campaign, float sum, Currency currency, final boolean billingNotifications)
    {
        if (currency == null) {
            return campaignSumChangedOnSum(campaign, sum, billingNotifications);
        } else {
            return campaignSumChangedOnSum(campaign, sum, currency.toString(), billingNotifications);
        }
    }

    public Callable<Float> campaignRestIs(final int campaignID, final String currency) {
        return campaignRestIs(campaignID, currency, properties.isDirectUseRealNotifyOrder());
    }

    public Callable<Float> campaignRestIs(
            final int campaignID, final String currency, final boolean billingNotifications)
    {
        return new Callable<Float>() {
            public Float call() throws Exception {
                if (!billingNotifications) {
                    UserSteps.getInstance().balanceSteps().synchronizeWithBalance(campaignID);
                }
                return (Float) new BeanMap(getCampaignParams(currency, campaignID)).get(CampaignInfoMap.REST);
            }
        };
    }

    public Callable<Float> campaignSumIs(final int campaignID, final String currency) {
        return campaignSumIs(campaignID, currency, properties.isDirectUseRealNotifyOrder());
    }

    public Callable<Float> campaignSumIs(
            final int campaignID, final String currency, final boolean billingNotifications)
    {
        return new Callable<Float>() {
            public Float call() throws Exception {
                if (!billingNotifications) {
                    UserSteps.getInstance().balanceSteps().synchronizeWithBalance(campaignID);
                }
                return (Float) new BeanMap(getCampaignParams(currency, campaignID)).get(CampaignInfoMap.SUM);
            }
        };
    }

    public Callable<Boolean> campaingIsActive(final int campaignId) {
        return new Callable<Boolean>() {
            public Boolean call() throws Exception {
                return ReflectionUtils
                        .invokeGetter(getCampaignParams(campaignId), StringUtils.capitalize(CampaignInfoMap.IS_ACTIVE))
                        .equals(Value.YES);
            }
        };
    }

    public Callable<Boolean> hasActiveCampaign(final String login) {
        return new Callable<Boolean>() {
            public Boolean call() throws Exception {
                return getActiveCampaigns(login).size() > 0;
            }
        };
    }

    public Callable<String> campaignStatusModerateIs(final int campaignID) {
        return () -> (String) new BeanMap(getCampaignParams(campaignID)).get(CampaignInfoMap.STATUS_MODERATE);
    }
    //endregion

    //region GetCampaignsList(Filter)
    @Step("[GetCampaignsList]: logins = {0}")
    public int[] getClientCampaigns(String login) {
        try {
            Object campaigns = getCampaignsList(login);
            List<Object> clientCampaigns =
                    JsonPath.read(JsonUtils.toString(campaigns),
                            "$.[?]", Filter.filter(Criteria.where("AgencyName").exists(false)));
            return ArrayUtils.toPrimitive(getCampaignIDs(clientCampaigns));
        } catch (AxisError axisFault) {
            throw new DirectAPIException("Не удалось получить список кампаний", axisFault);
        }
    }

    public int[] getCampaignIDs(String login) {
        try {
            Object campaigns = getCampaignsList(login);
            return ArrayUtils.toPrimitive(getCampaignIDs(campaigns));
        } catch (AxisError axisFault) {
            throw new DirectAPIException("Не удалось получить список кампаний", axisFault);
        }
    }

    private Integer[] getCampaignIDs(Object campaigns) {
        List<Integer> ids = JsonPath.read(JsonUtils.toString(campaigns), "$.[*].CampaignID");
        Integer[] result = ids.toArray(new Integer[0]);
        return result;
    }

    @Step("[GetCampaignsList]")
    public <T> T[] getCampaignsList(String... logins) {
        Object[] campaigns = new Object[0];
        campaigns = (Object[]) jsonClient().invokeMethod(
                Method.GET_CAMPAIGNS_LIST, logins);
        return (T[]) campaigns;
    }

    @Step("[GetCampaignsListFilter]")
    public <T> T[] getCampaignsListFilter(GetCampaignsInfoMap getCampaignsInfo) {
        Object[] campaign = new Object[0];
        campaign = (Object[]) jsonClient().invokeMethod(
                Method.GET_CAMPAIGNS_LIST_FILTER, getCampaignsInfo.getBean());
        return (T[]) campaign;
    }

    public <T> T getCampaignFromGetCampaignsList(String login, final int campaignId) {
        Object[] campaigns = getCampaignsList(login);
        return (T) CollectionUtils.find(Arrays.asList(campaigns), new Predicate() {
            public boolean evaluate(Object o) {
                return ((Integer) new CampaignInfoMap(o).get(uncapitalize(CampaignInfoMap.CAMPAIGN_ID))) == campaignId;
            }
        });
    }

    public <ShortCampaignInfo> ShortCampaignInfo getCampaignFromGetCampaignsListFilter(String login,
            final int campaignId)
    {
        return getCampaignFromGetCampaignsListFilter(
                new GetCampaignsInfoMap(connectionConfig.getPackage())
                        .withLogins(login),
                campaignId
        );
    }

    public <ShortCampaignInfo> ShortCampaignInfo getCampaignFromGetCampaignsListFilter(
            GetCampaignsInfoMap getCampaignsInfo, final int campaignId)
    {
        Object[] campaigns = getCampaignsListFilter(getCampaignsInfo);
        return (ShortCampaignInfo) CollectionUtils.find(Arrays.asList(campaigns), new Predicate() {
            public boolean evaluate(Object o) {
                return ((Integer) new CampaignInfoMap(o).get(uncapitalize(CampaignInfoMap.CAMPAIGN_ID))) == campaignId;
            }
        });
    }


    //endregion
    //region Delete campaign
    @Step("[DeleteCampaign]: campaignID = {0}")
    public void deleteCampaign(int campaignID) {
        //log.info("Удаление кампании campaignID = " + campaignID);
        CampaignIDInfoMap campaignIDInfoMap =
                new CampaignIDInfoMap(connectionConfig.getPackage())
                        .withCampaignID(campaignID);
        jsonClient().invokeMethod(Method.DELETE_CAMPAIGN, campaignIDInfoMap.getBean());
        bin.removeFromBin(campaignID);
        //log.info("Кампания удалена");
    }

    public void deleteCampaignsQuietly(Integer... campaignIDs) {
        for (int campaignID : campaignIDs) {
            try {
                deleteCampaign(campaignID);
            } catch (Exception e) {
                //log.info("Ошибка удаления кампании");
            }

        }
    }

    public void shouldGetErrorOnDeleteCampaign(AxisError axisError, int campaignID) {
        CampaignIDInfoMap campaignIDInfoMap =
                new CampaignIDInfoMap(connectionConfig.getPackage())
                        .withCampaignID(campaignID);
        shouldGetErrorOn(Method.DELETE_CAMPAIGN, campaignIDInfoMap, axisError);
    }

    //endregion


    //region Archive/Unarchive/Resume/Stop Campaign
    @Step("[ArchiveCampaign]: campaignID = {0}")
    public int archiveCampaign(int campaignID) {
        CampaignIDInfoMap campaignIDInfoMap =
                new CampaignIDInfoMap(connectionConfig.getPackage())
                        .withCampaignID(campaignID);
        return jsonClient().invokeMethod(Method.ARCHIVE_CAMPAIGN, campaignIDInfoMap.getBean());
    }

    @Step("Архивация списка кампаний campaignIDs = {0}")
    public void archiveCampaigns(int... campaignIDs) {
        for (int campaignID : campaignIDs) {
            archiveCampaign(campaignID);
        }
    }

    public void shouldGetErrorOnArchiveCampaign(AxisError axisError, int campaignID) {
        CampaignIDInfoMap campaignIDInfoMap =
                new CampaignIDInfoMap(connectionConfig.getPackage())
                        .withCampaignID(campaignID);
        shouldGetErrorOn(Method.ARCHIVE_CAMPAIGN, campaignIDInfoMap, axisError);
    }

    @Step("[UnArchiveCampaign]: campaignID = {0}")
    public int unArchiveCampaign(int campaignID) {
        CampaignIDInfoMap campaignIDInfoMap =
                new CampaignIDInfoMap(connectionConfig.getPackage())
                        .withCampaignID(campaignID);
        return jsonClient().invokeMethod(Method.UNARCHIVE_CAMPAIGN, campaignIDInfoMap.getBean());
    }

    @Step("Разархивация списка кампаний campaignIDs = {0}")
    public void unArchiveCampaign(int... campaignIDs) {
        for (int campaignID : campaignIDs) {
            unArchiveCampaign(campaignID);
        }
    }

    public void shouldGetErrorOnUnArchiveCampaign(AxisError axisError, int campaignID) {
        CampaignIDInfoMap campaignIDInfoMap =
                new CampaignIDInfoMap(connectionConfig.getPackage())
                        .withCampaignID(campaignID);
        shouldGetErrorOn(Method.UNARCHIVE_CAMPAIGN, campaignIDInfoMap, axisError);
    }

    @Step("[ResumeCampaign]: campaignID = {0}")
    public void resumeCampaign(int campaignID) {
        CampaignIDInfoMap campaignIDInfoMap =
                new CampaignIDInfoMap(connectionConfig.getPackage())
                        .withCampaignID(campaignID);
        jsonClient().invokeMethod(Method.RESUME_CAMPAIGN, campaignIDInfoMap.getBean());
    }

    public void shouldGetErrorOnResumeCampaign(AxisError axisError, int campaignID) {
        CampaignIDInfoMap campaignIDInfoMap =
                new CampaignIDInfoMap(connectionConfig.getPackage())
                        .withCampaignID(campaignID);
        shouldGetErrorOn(Method.RESUME_CAMPAIGN, campaignIDInfoMap, axisError);
    }

    @Step("[StopCampaign]: campaignID = {0}")
    public void stopCampaign(int campaignID) {
        CampaignIDInfoMap campaignIDInfoMap =
                new CampaignIDInfoMap(connectionConfig.getPackage())
                        .withCampaignID(campaignID);
        jsonClient().invokeMethod(Method.STOP_CAMPAIGN, campaignIDInfoMap.getBean());
    }

    public void stopCampaigns(int... campaignIDs) {
        for (int campaignID : campaignIDs) {
            stopCampaign(campaignID);
        }
    }

    public void shouldGetErrorOnStopCampaign(AxisError axisError, int campaignID) {
        CampaignIDInfoMap campaignIDInfoMap =
                new CampaignIDInfoMap(connectionConfig.getPackage())
                        .withCampaignID(campaignID);
        shouldGetErrorOn(Method.STOP_CAMPAIGN, campaignIDInfoMap, axisError);
    }
    //endregion

    @Step("[GetStatGoals]: campaignIDs = {0}")
    public <T> T[] getStatGoals(int... campaignIDs) {
        CampaignIDsInfoMap campaignIDsInfoMap =
                new CampaignIDsInfoMap(connectionConfig.getPackage())
                        .withCampaignIDs(campaignIDs);
        Object[] statGoals = new Object[0];
        statGoals = (Object[]) jsonClient().invokeMethod(
                Method.GET_STAT_GOALS, campaignIDsInfoMap.getBean());
        return (T[]) statGoals;
    }

    public void shouldGetErrorOnGetStatGoals(AxisError axisError, int... campaignIDs) {
        CampaignIDsInfoMap campaignIDsInfoMap =
                new CampaignIDsInfoMap(connectionConfig.getPackage())
                        .withCampaignIDs(campaignIDs);
        shouldGetErrorOn(Method.GET_STAT_GOALS, campaignIDsInfoMap, axisError);
    }

    public String getCampaignName(int campaignID) {
        try {
            return (String) new BeanMap(getCampaignParams(campaignID)).get(CampaignInfoMap.NAME);
        } catch (AxisError axisFault) {
            return "";
        }
    }

    @Step("Проверка права на редактирование кампании {0}")
    public void rightsForCampaign(int campaignID, Matcher<Boolean> matcher) {
        boolean result = false;
        try {
            Object campaign = getCampaignParams(campaignID);
            createOrUpdateCampaign(new CampaignInfoMap(campaign));
            result = true;
        } catch (AxisError error) {
            if (error.getErrorCode() == 54) {
                result = false;
            } else {
                throw new DirectAPIException("Недопустимая ошибка", error);
            }
        }
        TestSteps.assertThat("доступ на запись к кампании соответствует ожидаемому", result, matcher);
    }

    public <CampaignInfo> void campaignShouldHasStrategy(
            CampaignInfo campaign, StrategyMap strategyMap, StrategyMap contextStrategyMap)
    {
        CampaignInfoMap actualCampaignMap = new CampaignInfoMap(campaign);
        CampaignInfoMap expectedCampaign = new CampaignInfoMap(connectionConfig.getPackage())
                .withCampaignID((Integer) actualCampaignMap.get(CampaignInfoMap.CAMPAIGN_ID))
                .withStrategy(strategyMap)
                .withContextStrategy(contextStrategyMap)
                .withContextLimit((String) actualCampaignMap.get(CampaignInfoMap.CONTEXT_LIMIT))
                .withContextLimitSum((Integer) actualCampaignMap.get(CampaignInfoMap.CONTEXT_LIMIT_SUM))
                .withContextPricePercent((Integer) actualCampaignMap.get(CampaignInfoMap.CONTEXT_PRICE_PERCENT));

        BeanCompareStrategy beanCompareStrategy = new BeanCompareStrategy();
        beanCompareStrategy.putFieldMatcher(
                CampaignInfoMap.STRATEGY,
                BeanEquals.beanEquals(strategyMap.getBean()));
        beanCompareStrategy.putFieldMatcher(
                CampaignInfoMap.CONTEXT_STRATEGY,
                BeanEquals.beanEquals(contextStrategyMap.getBean()));

        String contextStrategyName = contextStrategyMap.getStrategyName();
        String contextLimit = StrategyMap.StrategyName.DEFAULT;
        Integer contextLimitSum = null;
        Integer contextPricePercent = 100;
        if (contextStrategyName.equals(StrategyMap.StrategyName.SHOWS_DISABLED)) {
            contextLimit = StrategyMap.StrategyName.LIMITED;
            contextLimitSum = 0;
            contextPricePercent = 100;
        } else if (contextStrategyName.equals(StrategyMap.StrategyName.DEFAULT)) {
            contextLimit = contextStrategyMap.get(CampaignInfoMap.CONTEXT_LIMIT) == null ?
                    contextLimit : (String) contextStrategyMap.get(CampaignInfoMap.CONTEXT_LIMIT);
            contextLimitSum = contextStrategyMap.get(CampaignInfoMap.CONTEXT_LIMIT_SUM) == null ?
                    contextLimitSum : (Integer) contextStrategyMap.get(CampaignInfoMap.CONTEXT_LIMIT_SUM);
            contextPricePercent = contextStrategyMap.get(CampaignInfoMap.CONTEXT_PRICE_PERCENT) == null ?
                    contextPricePercent : (Integer) contextStrategyMap.get(CampaignInfoMap.CONTEXT_PRICE_PERCENT);
        }
        beanCompareStrategy.putFieldMatcher(CampaignInfoMap.CONTEXT_LIMIT, equalTo(contextLimit));
        beanCompareStrategy.putFieldMatcher(CampaignInfoMap.CONTEXT_LIMIT_SUM, equalTo(contextLimitSum));
        beanCompareStrategy.putFieldMatcher(CampaignInfoMap.CONTEXT_PRICE_PERCENT, equalTo(contextPricePercent));


        TestSteps.assertThat("у кампании выставлена верная стратегия",
                campaign,
                BeanEquals.beanEquals(expectedCampaign.getBean())
                        .accordingStrategy(beanCompareStrategy)
                        .byFields(
                                CampaignInfoMap.CAMPAIGN_ID,
                                CampaignInfoMap.STRATEGY,
                                CampaignInfoMap.CONTEXT_STRATEGY,
                                CampaignInfoMap.CONTEXT_LIMIT,
                                CampaignInfoMap.CONTEXT_LIMIT_SUM,
                                CampaignInfoMap.CONTEXT_PRICE_PERCENT)

        );

    }
    //endregion

}
