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

import com.yandex.direct.api.v5.campaigns.SmartCampaignNetworkStrategy
import com.yandex.direct.api.v5.campaigns.SmartCampaignNetworkStrategyTypeEnum
import com.yandex.direct.api.v5.campaigns.SmartCampaignSearchStrategy
import com.yandex.direct.api.v5.campaigns.SmartCampaignSearchStrategyTypeEnum
import com.yandex.direct.api.v5.campaigns.SmartCampaignStrategy
import org.slf4j.LoggerFactory
import ru.yandex.direct.core.entity.campaign.model.DbStrategy
import ru.yandex.direct.core.entity.campaign.model.SmartCampaign
import ru.yandex.direct.core.entity.campaign.model.StrategyName
import java.lang.invoke.MethodHandles

private val logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass())

fun createSmartCampaignGetStrategy(campaign: SmartCampaign): SmartCampaignStrategy {
    val biddingStrategy =
        toSmartCampaignExternalStrategy(campaign.strategy, campaign.contextLimit)

    return biddingStrategy.apply {
        if (search.biddingStrategyType == null) {
            search.biddingStrategyType = SmartCampaignSearchStrategyTypeEnum.UNKNOWN
            logger.warn("Campaign ${campaign.id} has unknown strategy ${campaign.strategy}")
        }

        if (network.biddingStrategyType == null) {
            network.biddingStrategyType = SmartCampaignNetworkStrategyTypeEnum.UNKNOWN
            logger.warn("Campaign ${campaign.id} has unknown strategy ${campaign.strategy}")
        }

        // при автобюджетной стратегии в сетях NetworkDefault не заполняется
        // https://a.yandex-team.ru/arc_vcs/direct/perl/api/services/v5/API/Service/Campaigns.pm?rev=r9289187#L344-353
        if (campaign.strategy.strategyName.name.startsWith("AUTOBUDGET")) {
            biddingStrategy.network.networkDefault = null
        }
    }
}

fun toSmartCampaignExternalStrategy(
    internalStrategy: DbStrategy,
    contextLimit: Int?
) =
    SmartCampaignStrategy().apply {
        search = getSearchStrategy(internalStrategy)
        network = getNetworkStrategy(internalStrategy, contextLimit)
    }

private fun getSearchStrategy(internalStrategy: DbStrategy): SmartCampaignSearchStrategy {
    val search = SmartCampaignSearchStrategy()
    if (!internalStrategy.platform.isSearch()) {
        search.biddingStrategyType = SmartCampaignSearchStrategyTypeEnum.SERVING_OFF
    } else {
        val strategyData = internalStrategy.strategyData
        when (strategyData.name) {
            StrategyName.AUTOBUDGET_AVG_CPC_PER_CAMP.name.lowercase() -> {
                search.biddingStrategyType = SmartCampaignSearchStrategyTypeEnum.AVERAGE_CPC_PER_CAMPAIGN
                search.averageCpcPerCampaign = toStrategyAverageCpcPerCampaign(strategyData)
            }
            StrategyName.AUTOBUDGET_AVG_CPC_PER_FILTER.name.lowercase() -> {
                search.biddingStrategyType = SmartCampaignSearchStrategyTypeEnum.AVERAGE_CPC_PER_FILTER
                search.averageCpcPerFilter = toStrategyAverageCpcPerFilter(strategyData)
            }
            StrategyName.AUTOBUDGET_AVG_CPA_PER_CAMP.name.lowercase() -> {
                if (strategyData.payForConversion == true) {
                    search.biddingStrategyType = SmartCampaignSearchStrategyTypeEnum.PAY_FOR_CONVERSION_PER_CAMPAIGN
                    search.payForConversionPerCampaign = toStrategyPayForConversionPerCampaign(strategyData)
                } else {
                    search.biddingStrategyType = SmartCampaignSearchStrategyTypeEnum.AVERAGE_CPA_PER_CAMPAIGN
                    search.averageCpaPerCampaign = toStrategyAverageCpaPerCampaign(strategyData)
                }
            }
            StrategyName.AUTOBUDGET_AVG_CPA_PER_FILTER.name.lowercase() -> {
                if (strategyData.payForConversion == true) {
                    search.biddingStrategyType = SmartCampaignSearchStrategyTypeEnum.PAY_FOR_CONVERSION_PER_FILTER
                    search.payForConversionPerFilter = toStrategyPayForConversionPerFilter(strategyData)
                } else {
                    search.biddingStrategyType = SmartCampaignSearchStrategyTypeEnum.AVERAGE_CPA_PER_FILTER
                    search.averageCpaPerFilter = toStrategyAverageCpaPerFilter(strategyData)
                }
            }
            StrategyName.AUTOBUDGET.name.lowercase() -> {
                search.biddingStrategyType = SmartCampaignSearchStrategyTypeEnum.WB_MAXIMUM_CONVERSION_RATE
                search.wbMaximumConversionRate = toStrategyMaximumConversionRate(strategyData)
            }
            StrategyName.AUTOBUDGET_CRR.name.lowercase() -> {
                if (strategyData.payForConversion == true) {
                    search.biddingStrategyType = SmartCampaignSearchStrategyTypeEnum.PAY_FOR_CONVERSION_CRR
                    search.payForConversionCrr = toStrategyPayForConversionCrr(strategyData)
                } else {
                    search.biddingStrategyType = SmartCampaignSearchStrategyTypeEnum.AVERAGE_CRR
                    search.averageCrr = toStrategyAverageCrr(strategyData)
                }
            }
            StrategyName.AUTOBUDGET_ROI.name.lowercase() -> {
                search.biddingStrategyType = SmartCampaignSearchStrategyTypeEnum.AVERAGE_ROI
                search.averageRoi = toStrategyAverageRoi(strategyData)
            }
        }
    }
    return search
}

private fun getNetworkStrategy(
    internalStrategy: DbStrategy,
    contextLimit: Int?
): SmartCampaignNetworkStrategy {
    val network = SmartCampaignNetworkStrategy()
    if (internalStrategy.platform.isBoth()) {
        network.biddingStrategyType = SmartCampaignNetworkStrategyTypeEnum.NETWORK_DEFAULT
        network.networkDefault = toStrategyNetworkDefault(contextLimit)
    } else if (!internalStrategy.platform.isNetwork()) {
        network.biddingStrategyType = SmartCampaignNetworkStrategyTypeEnum.SERVING_OFF
    } else {
        val strategyData = internalStrategy.strategyData
        when (strategyData.name) {
            StrategyName.AUTOBUDGET_AVG_CPC_PER_CAMP.name.lowercase() -> {
                network.biddingStrategyType = SmartCampaignNetworkStrategyTypeEnum.AVERAGE_CPC_PER_CAMPAIGN
                network.averageCpcPerCampaign = toStrategyAverageCpcPerCampaign(strategyData)
            }
            StrategyName.AUTOBUDGET_AVG_CPC_PER_FILTER.name.lowercase() -> {
                network.biddingStrategyType = SmartCampaignNetworkStrategyTypeEnum.AVERAGE_CPC_PER_FILTER
                network.averageCpcPerFilter = toStrategyAverageCpcPerFilter(strategyData)
            }
            StrategyName.AUTOBUDGET_AVG_CPA_PER_CAMP.name.lowercase() -> {
                if (strategyData.payForConversion == true) {
                    network.biddingStrategyType = SmartCampaignNetworkStrategyTypeEnum.PAY_FOR_CONVERSION_PER_CAMPAIGN
                    network.payForConversionPerCampaign = toStrategyPayForConversionPerCampaign(strategyData)
                } else {
                    network.biddingStrategyType = SmartCampaignNetworkStrategyTypeEnum.AVERAGE_CPA_PER_CAMPAIGN
                    network.averageCpaPerCampaign = toStrategyAverageCpaPerCampaign(strategyData)
                }
            }
            StrategyName.AUTOBUDGET_AVG_CPA_PER_FILTER.name.lowercase() -> {
                if (strategyData.payForConversion == true) {
                    network.biddingStrategyType = SmartCampaignNetworkStrategyTypeEnum.PAY_FOR_CONVERSION_PER_FILTER
                    network.payForConversionPerFilter = toStrategyPayForConversionPerFilter(strategyData)
                } else {
                    network.biddingStrategyType = SmartCampaignNetworkStrategyTypeEnum.AVERAGE_CPA_PER_FILTER
                    network.averageCpaPerFilter = toStrategyAverageCpaPerFilter(strategyData)
                }
            }
            StrategyName.AUTOBUDGET.name.lowercase() -> {
                network.biddingStrategyType = SmartCampaignNetworkStrategyTypeEnum.WB_MAXIMUM_CONVERSION_RATE
                network.wbMaximumConversionRate = toStrategyMaximumConversionRate(strategyData)
            }
            StrategyName.AUTOBUDGET_CRR.name.lowercase() -> {
                if (strategyData.payForConversion == true) {
                    network.biddingStrategyType = SmartCampaignNetworkStrategyTypeEnum.PAY_FOR_CONVERSION_CRR
                    network.payForConversionCrr = toStrategyPayForConversionCrr(strategyData)
                } else {
                    network.biddingStrategyType = SmartCampaignNetworkStrategyTypeEnum.AVERAGE_CRR
                    network.averageCrr = toStrategyAverageCrr(strategyData)
                }
            }
            StrategyName.AUTOBUDGET_ROI.name.lowercase() -> {
                network.biddingStrategyType = SmartCampaignNetworkStrategyTypeEnum.AVERAGE_ROI
                network.averageRoi = toStrategyAverageRoi(strategyData)
            }
        }
    }
    return network
}
