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

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.ParametersAreNonnullByDefault;

import com.yandex.direct.api.v5.campaigns.CampaignAddItem;
import com.yandex.direct.api.v5.campaigns.DynamicTextCampaignAddItem;
import com.yandex.direct.api.v5.campaigns.DynamicTextCampaignSetting;
import com.yandex.direct.api.v5.campaigns.DynamicTextCampaignSettingsEnum;
import com.yandex.direct.api.v5.general.YesNoEnum;
import one.util.streamex.StreamEx;

import ru.yandex.direct.api.v5.entity.campaigns.validation.CampaignsApiValidationSignals;
import ru.yandex.direct.core.entity.campaign.model.BroadMatch;
import ru.yandex.direct.core.entity.campaign.model.CampaignSource;
import ru.yandex.direct.core.entity.campaign.model.CampaignType;
import ru.yandex.direct.core.entity.campaign.model.DbStrategy;
import ru.yandex.direct.core.entity.campaign.model.DynamicCampaign;
import ru.yandex.direct.core.entity.timetarget.model.GeoTimezone;

import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractCheckPositionIntervalEvent;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractDayBudget;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractDayBudgetShowMode;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractDisabledDomains;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractDisabledIps;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractDisabledSsp;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractEmail;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractEnableCheckPositionEvent;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractMeaningfulGoals;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractMinusKeywords;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractPlacementTypes;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractSendAccountNews;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractSmsFlags;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractSmsTimeInterval;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractTimeTarget;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.extractWarningBalance;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.getEnableCpcHold;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.toAttributionModel;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.CampaignDataConverterKt.toDate;
import static ru.yandex.direct.api.v5.entity.campaigns.converter.DynamicTextCampaignStrategyConverter.toCampaignStrategy;
import static ru.yandex.direct.core.entity.campaign.service.validation.CampaignConstants.DEFAULT_ADD_METRIKA_TAG_TO_URL;
import static ru.yandex.direct.core.entity.campaign.service.validation.CampaignConstants.DEFAULT_ADD_OPENSTAT_TAG_TO_URL;
import static ru.yandex.direct.core.entity.campaign.service.validation.CampaignConstants.DEFAULT_ADD_TO_FAVORITES;
import static ru.yandex.direct.core.entity.campaign.service.validation.CampaignConstants.DEFAULT_ENABLE_COMPANY_INFO;
import static ru.yandex.direct.core.entity.campaign.service.validation.CampaignConstants.DEFAULT_HAS_EXTENDED_GEO_TARGETING;
import static ru.yandex.direct.core.entity.campaign.service.validation.CampaignConstants.DEFAULT_HAS_SITE_MONITORING;
import static ru.yandex.direct.core.entity.campaign.service.validation.CampaignConstants.DEFAULT_HAS_TITLE_SUBSTITUTION;
import static ru.yandex.direct.utils.CommonUtils.nvl;

@ParametersAreNonnullByDefault
public class DynamicTextCampaignAddItemConverter {

    // CAMPAIGN_EXACT_PHRASE_MATCHING_ENABLED (IS_ORDER_PHRASE_LENGTH_PRECEDENCE_ENABLED в модели) - должно быть null,
    // если у пользователя нет фичи, смотри CampaignWithOrderPhraseLengthPrecedenceForbiddenValidator, поэтому  дефолт
    // не проставляем, чтобы не перезатиреть null
    // ENABLE_RELATED_KEYWORDS, ENABLE_AUTOFOCUS, ENABLE_BEHAVIORAL_TARGETING - deprecated
    private static final Map<DynamicTextCampaignSettingsEnum, Boolean> DEFAULT_SETTINGS = Map.of(
            DynamicTextCampaignSettingsEnum.ADD_METRICA_TAG, DEFAULT_ADD_METRIKA_TAG_TO_URL,
            DynamicTextCampaignSettingsEnum.ADD_OPENSTAT_TAG, DEFAULT_ADD_OPENSTAT_TAG_TO_URL,
            DynamicTextCampaignSettingsEnum.ENABLE_AREA_OF_INTEREST_TARGETING, DEFAULT_HAS_EXTENDED_GEO_TARGETING,
            DynamicTextCampaignSettingsEnum.ENABLE_COMPANY_INFO, DEFAULT_ENABLE_COMPANY_INFO,
            DynamicTextCampaignSettingsEnum.ENABLE_EXTENDED_AD_TITLE, DEFAULT_HAS_TITLE_SUBSTITUTION,
            DynamicTextCampaignSettingsEnum.ENABLE_SITE_MONITORING, DEFAULT_HAS_SITE_MONITORING,
            DynamicTextCampaignSettingsEnum.ADD_TO_FAVORITES, DEFAULT_ADD_TO_FAVORITES
    );

    public static CampaignsApiValidationSignals.CampaignWrapper convertDynamicTextCampaign(
            CampaignAddItem item,
            Long chiefUid,
            String userEmail,
            Map<String, GeoTimezone> timeZones,
            CampaignSource campaignSource,
            Set<String> knownSsps,
            boolean advancedGeoTargeting) {
        DynamicTextCampaignAddItem dynamicCampaignItem = item.getDynamicTextCampaign();

        Map<DynamicTextCampaignSettingsEnum, Boolean> settings = convertDynamicTextCampaignSettings(
                dynamicCampaignItem.getSettings(), advancedGeoTargeting);
        Set<Long> favoriteForUids = settings.get(DynamicTextCampaignSettingsEnum.ADD_TO_FAVORITES) ?
                Set.of(chiefUid) : null;

        DbStrategy strategy = toCampaignStrategy(dynamicCampaignItem.getBiddingStrategy());

        var campaign = new DynamicCampaign()
                .withSource(campaignSource)
                .withType(CampaignType.DYNAMIC)
                .withName(item.getName())
                .withStrategy(strategy)
                .withHasAddMetrikaTagToUrl(settings.get(DynamicTextCampaignSettingsEnum.ADD_METRICA_TAG))
                .withHasAddOpenstatTagToUrl(settings.get(DynamicTextCampaignSettingsEnum.ADD_OPENSTAT_TAG))
                .withHasExtendedGeoTargeting(settings.get(DynamicTextCampaignSettingsEnum.ENABLE_AREA_OF_INTEREST_TARGETING))
                .withUseCurrentRegion(settings.get(DynamicTextCampaignSettingsEnum.ENABLE_CURRENT_AREA_TARGETING))
                .withUseRegularRegion(settings.get(DynamicTextCampaignSettingsEnum.ENABLE_REGULAR_AREA_TARGETING))
                .withEnableCompanyInfo(settings.get(DynamicTextCampaignSettingsEnum.ENABLE_COMPANY_INFO))
                .withHasTitleSubstitution(settings.get(DynamicTextCampaignSettingsEnum.ENABLE_EXTENDED_AD_TITLE))
                .withHasSiteMonitoring(settings.get(DynamicTextCampaignSettingsEnum.ENABLE_SITE_MONITORING))
                .withEnableCpcHold(getEnableCpcHold(strategy.isAutoBudget()))
                .withIsOrderPhraseLengthPrecedenceEnabled(
                        settings.get(DynamicTextCampaignSettingsEnum.CAMPAIGN_EXACT_PHRASE_MATCHING_ENABLED))
                .withFavoriteForUids(favoriteForUids)
                .withStartDate(toDate(item.getStartDate()))
                .withEndDate(toDate(item.getEndDate()))
                .withEmail(userEmail)
                .withSmsTime(extractSmsTimeInterval(item))
                .withSmsFlags(extractSmsFlags(item))
                .withDayBudget(extractDayBudget(item))
                .withDayBudgetShowMode(extractDayBudgetShowMode(item))
                // В API5 RelevantKeywords не реализованы для DynamicTextCampaign поэтому здесь проставляем "отключены"
                .withBroadMatch(new BroadMatch()
                        .withBroadMatchFlag(false)
                        .withBroadMatchLimit(0)
                        .withBroadMatchGoalId(0L))
                .withTimeZoneId(item.getTimeZone() == null ? 0 : timeZones.get(item.getTimeZone()).getTimezoneId())
                .withTimeTarget(extractTimeTarget(item))
                .withMetrikaCounters(CampaignsAddRequestConverter.toMetrikaCounters(
                        dynamicCampaignItem.getCounterIds()))
                .withFio(item.getClientInfo())
                .withMinusKeywords(extractMinusKeywords(item))
                .withEmail(nvl(extractEmail(item.getNotification()), userEmail))
                .withWarningBalance(extractWarningBalance(item.getNotification()))
                .withCheckPositionIntervalEvent(extractCheckPositionIntervalEvent(item.getNotification()))
                .withEnableSendAccountNews(extractSendAccountNews(item))
                .withEnableCheckPositionEvent(extractEnableCheckPositionEvent(item.getNotification()))
                .withDisabledIps(extractDisabledIps(item))
                .withDisabledSsp(extractDisabledSsp(item, knownSsps))
                .withDisabledDomains(extractDisabledDomains(item, knownSsps))
                .withPlacementTypes(extractPlacementTypes(dynamicCampaignItem))
                .withAttributionModel(toAttributionModel(dynamicCampaignItem.getAttributionModel()))
                .withMeaningfulGoals(extractMeaningfulGoals(dynamicCampaignItem))
                .withStrategyId(dynamicCampaignItem.getStrategyId())
                .withBannerHrefParams(dynamicCampaignItem.getTrackingParams());

        return new CampaignsApiValidationSignals.CampaignWrapper()
                .withRealCampaign(campaign)
                .withRequireServicing(settings.get(DynamicTextCampaignSettingsEnum.REQUIRE_SERVICING));
    }

    private static Map<DynamicTextCampaignSettingsEnum, Boolean> convertDynamicTextCampaignSettings(
            List<DynamicTextCampaignSetting> settings, boolean advancedGeoTargeting) {
        Map<DynamicTextCampaignSettingsEnum, Boolean> valueByOption = new HashMap<>();
        for (DynamicTextCampaignSetting s : settings) {
            valueByOption.put(s.getOption(), s.getValue() == YesNoEnum.YES);
        }
        if (advancedGeoTargeting) {
            if (!valueByOption.containsKey(DynamicTextCampaignSettingsEnum.ENABLE_CURRENT_AREA_TARGETING)) {
                valueByOption.put(DynamicTextCampaignSettingsEnum.ENABLE_CURRENT_AREA_TARGETING, true);
            }
            if (!valueByOption.containsKey(DynamicTextCampaignSettingsEnum.ENABLE_REGULAR_AREA_TARGETING)) {
                valueByOption.put(DynamicTextCampaignSettingsEnum.ENABLE_REGULAR_AREA_TARGETING, true);
            }
        }
        return StreamEx.of(DynamicTextCampaignSettingsEnum.values())
                .mapToEntry(option -> valueByOption.getOrDefault(option, DEFAULT_SETTINGS.get(option)))
                .nonNullValues()
                .toMap();
    }

}
