package ru.yandex.direct.api.v5.entity.campaigns.converter;

import java.util.Map;

import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;

import com.google.common.collect.ImmutableMap;
import com.yandex.direct.api.v5.campaigns.TextCampaignNetworkStrategy;
import com.yandex.direct.api.v5.campaigns.TextCampaignNetworkStrategyAdd;
import com.yandex.direct.api.v5.campaigns.TextCampaignNetworkStrategyTypeEnum;
import com.yandex.direct.api.v5.campaigns.TextCampaignSearchStrategy;
import com.yandex.direct.api.v5.campaigns.TextCampaignSearchStrategyAdd;
import com.yandex.direct.api.v5.campaigns.TextCampaignSearchStrategyTypeEnum;
import com.yandex.direct.api.v5.campaigns.TextCampaignStrategy;
import com.yandex.direct.api.v5.campaigns.TextCampaignStrategyAdd;

import ru.yandex.direct.core.entity.campaign.model.CampOptionsStrategy;
import ru.yandex.direct.core.entity.campaign.model.CampaignsPlatform;
import ru.yandex.direct.core.entity.campaign.model.DbStrategy;
import ru.yandex.direct.core.entity.campaign.model.StrategyData;
import ru.yandex.direct.core.entity.campaign.model.StrategyName;

import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyAddConverter.defaultStrategyData;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyAddConverter.fromAverageCpa;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyAddConverter.fromAverageCpc;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyAddConverter.fromAverageCrr;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyAddConverter.fromAverageRoi;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyAddConverter.fromPayForConversion;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyAddConverter.fromPayForConversionCrr;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyAddConverter.fromWbMaximumClicks;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyAddConverter.fromWbMaximumConversionRate;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyAddConverter.fromWeeklyClickPackage;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyAddConverter.toCampaignsAutobudget;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyUpdateConverter.fromAverageCpa;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyUpdateConverter.fromAverageCpc;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyUpdateConverter.fromAverageCrr;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyUpdateConverter.fromAverageRoi;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyUpdateConverter.fromPayForConversion;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyUpdateConverter.fromPayForConversionCrr;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyUpdateConverter.fromWbMaximumClicks;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyUpdateConverter.fromWbMaximumConversionRate;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.StrategyUpdateConverter.fromWeeklyClickPackage;

@ParametersAreNonnullByDefault
public class TextCampaignStrategyConverter {

    // strategy_name_outer_to_inner
    // https://a.yandex-team.ru/arc/trunk/arcadia/direct/perl/api/services/v5/API/Service/Campaigns/Strategies.pm?rev=r8266602#L131
    private static final Map<TextCampaignSearchStrategyTypeEnum, StrategyName> STRATEGY_NAME_BY_SEARCH_STRATEGY_TYPE =
            ImmutableMap.<TextCampaignSearchStrategyTypeEnum, StrategyName>builder()
                    .put(TextCampaignSearchStrategyTypeEnum.AVERAGE_CPA, StrategyName.AUTOBUDGET_AVG_CPA)
                    .put(TextCampaignSearchStrategyTypeEnum.AVERAGE_CPC, StrategyName.AUTOBUDGET_AVG_CLICK)
                    .put(TextCampaignSearchStrategyTypeEnum.AVERAGE_ROI, StrategyName.AUTOBUDGET_ROI)
                    .put(TextCampaignSearchStrategyTypeEnum.AVERAGE_CRR, StrategyName.AUTOBUDGET_CRR)
                    .put(TextCampaignSearchStrategyTypeEnum.HIGHEST_POSITION, StrategyName.DEFAULT_)
                    .put(TextCampaignSearchStrategyTypeEnum.PAY_FOR_CONVERSION, StrategyName.AUTOBUDGET_AVG_CPA)
                    .put(TextCampaignSearchStrategyTypeEnum.PAY_FOR_CONVERSION_CRR, StrategyName.AUTOBUDGET_CRR)
                    .put(TextCampaignSearchStrategyTypeEnum.WB_MAXIMUM_CLICKS, StrategyName.AUTOBUDGET)
                    .put(TextCampaignSearchStrategyTypeEnum.WB_MAXIMUM_CONVERSION_RATE, StrategyName.AUTOBUDGET)
                    .put(TextCampaignSearchStrategyTypeEnum.WEEKLY_CLICK_PACKAGE, StrategyName.AUTOBUDGET_WEEK_BUNDLE)
                    .build();

    // context_strategy_name_outer_to_inner
    // https://a.yandex-team.ru/arc/trunk/arcadia/direct/perl/api/services/v5/API/Service/Campaigns/Strategies.pm?rev=r8266602#L165
    private static final Map<TextCampaignNetworkStrategyTypeEnum, StrategyName> STRATEGY_NAME_BY_NETWORK_STRATEGY_TYPE =
            ImmutableMap.<TextCampaignNetworkStrategyTypeEnum, StrategyName>builder()
                    .put(TextCampaignNetworkStrategyTypeEnum.AVERAGE_CPA, StrategyName.AUTOBUDGET_AVG_CPA)
                    .put(TextCampaignNetworkStrategyTypeEnum.AVERAGE_CPC, StrategyName.AUTOBUDGET_AVG_CLICK)
                    .put(TextCampaignNetworkStrategyTypeEnum.AVERAGE_ROI, StrategyName.AUTOBUDGET_ROI)
                    .put(TextCampaignNetworkStrategyTypeEnum.AVERAGE_CRR, StrategyName.AUTOBUDGET_CRR)
                    .put(TextCampaignNetworkStrategyTypeEnum.MAXIMUM_COVERAGE, StrategyName.DEFAULT_)
                    .put(TextCampaignNetworkStrategyTypeEnum.PAY_FOR_CONVERSION, StrategyName.AUTOBUDGET_AVG_CPA)
                    .put(TextCampaignNetworkStrategyTypeEnum.PAY_FOR_CONVERSION_CRR, StrategyName.AUTOBUDGET_CRR)
                    .put(TextCampaignNetworkStrategyTypeEnum.WB_MAXIMUM_CLICKS, StrategyName.AUTOBUDGET)
                    .put(TextCampaignNetworkStrategyTypeEnum.WB_MAXIMUM_CONVERSION_RATE, StrategyName.AUTOBUDGET)
                    .put(TextCampaignNetworkStrategyTypeEnum.WEEKLY_CLICK_PACKAGE, StrategyName.AUTOBUDGET_WEEK_BUNDLE)
                    .build();

    private TextCampaignStrategyConverter() {
    }

    public static DbStrategy toCampaignStrategy(TextCampaignStrategy apiStrategy) {
        var dbStrategy = new DbStrategy();

        TextCampaignSearchStrategyTypeEnum searchStrategyType = apiStrategy.getSearch().getBiddingStrategyType();
        TextCampaignNetworkStrategyTypeEnum networkStrategyType = apiStrategy.getNetwork().getBiddingStrategyType();

        if (STRATEGY_NAME_BY_SEARCH_STRATEGY_TYPE.containsKey(searchStrategyType)) {
            StrategyName strategyName = STRATEGY_NAME_BY_SEARCH_STRATEGY_TYPE.get(searchStrategyType);
            dbStrategy.withStrategyName(strategyName);
            dbStrategy.withAutobudget(toCampaignsAutobudget(strategyName));
            dbStrategy.withStrategyData(fromSearchStrategyData(searchStrategyType, apiStrategy.getSearch()));
        } else if (STRATEGY_NAME_BY_NETWORK_STRATEGY_TYPE.containsKey(networkStrategyType)) {
            StrategyName strategyName = STRATEGY_NAME_BY_NETWORK_STRATEGY_TYPE.get(networkStrategyType);
            dbStrategy.withStrategyName(strategyName);
            dbStrategy.withAutobudget(toCampaignsAutobudget(strategyName));
            dbStrategy.withStrategyData(fromNetworkStrategyData(networkStrategyType, apiStrategy.getNetwork()));
        } else {
            throw new IllegalStateException(String.format("Strategy is not defined (search: %s, network %s)",
                    searchStrategyType, networkStrategyType));
        }

        dbStrategy.withPlatform(toCampaignsPlatform(searchStrategyType, networkStrategyType));
        dbStrategy.withStrategy(toCampOptionsStrategy(networkStrategyType));
        return dbStrategy;
    }

    public static DbStrategy toCampaignStrategy(TextCampaignStrategyAdd apiStrategy) {
        var dbStrategy = new DbStrategy();

        TextCampaignSearchStrategyTypeEnum searchStrategyType = apiStrategy.getSearch().getBiddingStrategyType();
        TextCampaignNetworkStrategyTypeEnum networkStrategyType = apiStrategy.getNetwork().getBiddingStrategyType();

        if (STRATEGY_NAME_BY_SEARCH_STRATEGY_TYPE.containsKey(searchStrategyType)) {
            StrategyName strategyName = STRATEGY_NAME_BY_SEARCH_STRATEGY_TYPE.get(searchStrategyType);
            dbStrategy.withStrategyName(strategyName);
            dbStrategy.withAutobudget(toCampaignsAutobudget(strategyName));
            dbStrategy.withStrategyData(fromSearchStrategyData(searchStrategyType, apiStrategy.getSearch()));
        } else if (STRATEGY_NAME_BY_NETWORK_STRATEGY_TYPE.containsKey(networkStrategyType)) {
            StrategyName strategyName = STRATEGY_NAME_BY_NETWORK_STRATEGY_TYPE.get(networkStrategyType);
            dbStrategy.withStrategyName(strategyName);
            dbStrategy.withAutobudget(toCampaignsAutobudget(strategyName));
            dbStrategy.withStrategyData(fromNetworkStrategyData(networkStrategyType, apiStrategy.getNetwork()));
        } else {
            throw new IllegalStateException(String.format("Strategy is not defined (search: %s, network %s)",
                    searchStrategyType, networkStrategyType));
        }

        dbStrategy.withPlatform(toCampaignsPlatform(searchStrategyType, networkStrategyType));
        dbStrategy.withStrategy(toCampOptionsStrategy(networkStrategyType));
        return dbStrategy;
    }

    @Nullable
    private static CampaignsPlatform toCampaignsPlatform(TextCampaignSearchStrategyTypeEnum searchStrategyType,
                                                         TextCampaignNetworkStrategyTypeEnum networkStrategyType) {

        boolean isSearchStop = searchStrategyType == TextCampaignSearchStrategyTypeEnum.SERVING_OFF;
        boolean isNetworkStop = networkStrategyType == TextCampaignNetworkStrategyTypeEnum.SERVING_OFF;

        if (isSearchStop) {
            return isNetworkStop ? null : CampaignsPlatform.CONTEXT;
        } else {
            return isNetworkStop ? CampaignsPlatform.SEARCH : CampaignsPlatform.BOTH;
        }
    }

    @Nullable
    private static CampOptionsStrategy toCampOptionsStrategy(TextCampaignNetworkStrategyTypeEnum networkStrategyType) {
        boolean isDifferentPlaces = (networkStrategyType != TextCampaignNetworkStrategyTypeEnum.NETWORK_DEFAULT)
                && (networkStrategyType != TextCampaignNetworkStrategyTypeEnum.SERVING_OFF);
        return isDifferentPlaces ? CampOptionsStrategy.DIFFERENT_PLACES : null;
    }

    @Nullable
    private static StrategyData fromSearchStrategyData(TextCampaignSearchStrategyTypeEnum searchStrategyType,
                                                       TextCampaignSearchStrategyAdd strategy) {
        switch (searchStrategyType) {
            case HIGHEST_POSITION:
                return defaultStrategyData();

            case AVERAGE_CPA:
                return fromAverageCpa(strategy.getAverageCpa());

            case AVERAGE_CPC:
                return fromAverageCpc(strategy.getAverageCpc());

            case AVERAGE_CRR:
                return fromAverageCrr(strategy.getAverageCrr());

            case AVERAGE_ROI:
                return fromAverageRoi(strategy.getAverageRoi());

            case PAY_FOR_CONVERSION:
                return fromPayForConversion(strategy.getPayForConversion());

            case PAY_FOR_CONVERSION_CRR:
                return fromPayForConversionCrr(strategy.getPayForConversionCrr());

            case WB_MAXIMUM_CLICKS:
                return fromWbMaximumClicks(strategy.getWbMaximumClicks());

            case WB_MAXIMUM_CONVERSION_RATE:
                return fromWbMaximumConversionRate(strategy.getWbMaximumConversionRate());

            case WEEKLY_CLICK_PACKAGE:
                return fromWeeklyClickPackage(strategy.getWeeklyClickPackage());

            default:
                return null;
        }
    }

    @Nullable
    private static StrategyData fromNetworkStrategyData(TextCampaignNetworkStrategyTypeEnum networkStrategyType,
                                                        TextCampaignNetworkStrategyAdd strategy) {
        switch (networkStrategyType) {
            case MAXIMUM_COVERAGE:
                return defaultStrategyData();

            case AVERAGE_CPA:
                return fromAverageCpa(strategy.getAverageCpa());

            case AVERAGE_CPC:
                return fromAverageCpc(strategy.getAverageCpc());

            case AVERAGE_CRR:
                return fromAverageCrr(strategy.getAverageCrr());

            case AVERAGE_ROI:
                return fromAverageRoi(strategy.getAverageRoi());

            case PAY_FOR_CONVERSION:
                return fromPayForConversion(strategy.getPayForConversion());

            case PAY_FOR_CONVERSION_CRR:
                return fromPayForConversionCrr(strategy.getPayForConversionCrr());

            case WB_MAXIMUM_CLICKS:
                return fromWbMaximumClicks(strategy.getWbMaximumClicks());

            case WB_MAXIMUM_CONVERSION_RATE:
                return fromWbMaximumConversionRate(strategy.getWbMaximumConversionRate());

            case WEEKLY_CLICK_PACKAGE:
                return fromWeeklyClickPackage(strategy.getWeeklyClickPackage());

            default:
                return null;
        }
    }

    @Nullable
    private static StrategyData fromSearchStrategyData(TextCampaignSearchStrategyTypeEnum searchStrategyType,
                                                       TextCampaignSearchStrategy strategy) {
        switch (searchStrategyType) {
            case HIGHEST_POSITION:
                return defaultStrategyData();

            case AVERAGE_CPA:
                return fromAverageCpa(strategy.getAverageCpa());

            case AVERAGE_CPC:
                return fromAverageCpc(strategy.getAverageCpc());

            case AVERAGE_CRR:
                return fromAverageCrr(strategy.getAverageCrr());

            case AVERAGE_ROI:
                return fromAverageRoi(strategy.getAverageRoi());

            case PAY_FOR_CONVERSION:
                return fromPayForConversion(strategy.getPayForConversion());

            case PAY_FOR_CONVERSION_CRR:
                return fromPayForConversionCrr(strategy.getPayForConversionCrr());

            case WB_MAXIMUM_CLICKS:
                return fromWbMaximumClicks(strategy.getWbMaximumClicks());

            case WB_MAXIMUM_CONVERSION_RATE:
                return fromWbMaximumConversionRate(strategy.getWbMaximumConversionRate());

            case WEEKLY_CLICK_PACKAGE:
                return fromWeeklyClickPackage(strategy.getWeeklyClickPackage());

            default:
                return null;
        }
    }

    @Nullable
    private static StrategyData fromNetworkStrategyData(TextCampaignNetworkStrategyTypeEnum networkStrategyType,
                                                        TextCampaignNetworkStrategy strategy) {
        switch (networkStrategyType) {
            case MAXIMUM_COVERAGE:
                return defaultStrategyData();

            case AVERAGE_CPA:
                return fromAverageCpa(strategy.getAverageCpa());

            case AVERAGE_CPC:
                return fromAverageCpc(strategy.getAverageCpc());

            case AVERAGE_CRR:
                return fromAverageCrr(strategy.getAverageCrr());

            case AVERAGE_ROI:
                return fromAverageRoi(strategy.getAverageRoi());

            case PAY_FOR_CONVERSION:
                return fromPayForConversion(strategy.getPayForConversion());

            case PAY_FOR_CONVERSION_CRR:
                return fromPayForConversionCrr(strategy.getPayForConversionCrr());

            case WB_MAXIMUM_CLICKS:
                return fromWbMaximumClicks(strategy.getWbMaximumClicks());

            case WB_MAXIMUM_CONVERSION_RATE:
                return fromWbMaximumConversionRate(strategy.getWbMaximumConversionRate());

            case WEEKLY_CLICK_PACKAGE:
                return fromWeeklyClickPackage(strategy.getWeeklyClickPackage());

            default:
                return null;
        }
    }
}
