package ru.yandex.direct.web.entity.adgroup.converter;

import java.util.List;

import javax.annotation.Nullable;

import one.util.streamex.StreamEx;

import ru.yandex.direct.core.entity.adgroup.container.ComplexAdGroup;
import ru.yandex.direct.core.entity.adgroup.container.ComplexCpmAdGroup;
import ru.yandex.direct.core.entity.adgroup.model.AdGroup;
import ru.yandex.direct.core.entity.adgroup.model.AdGroupType;
import ru.yandex.direct.core.entity.adgroup.model.CpmAudioAdGroup;
import ru.yandex.direct.core.entity.adgroup.model.CpmBannerAdGroup;
import ru.yandex.direct.core.entity.adgroup.model.CpmGeoPinAdGroup;
import ru.yandex.direct.core.entity.adgroup.model.CpmGeoproductAdGroup;
import ru.yandex.direct.core.entity.adgroup.model.CpmIndoorAdGroup;
import ru.yandex.direct.core.entity.adgroup.model.CpmOutdoorAdGroup;
import ru.yandex.direct.core.entity.adgroup.model.CpmVideoAdGroup;
import ru.yandex.direct.core.entity.adgroup.model.CpmYndxFrontpageAdGroup;
import ru.yandex.direct.core.entity.campaign.model.CampaignType;
import ru.yandex.direct.web.entity.adgroup.model.WebCpmAdGroup;

import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format;
import static org.apache.commons.collections4.CollectionUtils.isEmpty;
import static ru.yandex.direct.core.entity.adgroup.model.CriterionType.KEYWORD;
import static ru.yandex.direct.core.entity.adgroup.model.CriterionType.USER_PROFILE;
import static ru.yandex.direct.utils.FunctionalUtils.mapList;
import static ru.yandex.direct.web.entity.adgroup.converter.AdGroupBidModifiersConverter.webAdGroupBidModifiersToCore;
import static ru.yandex.direct.web.entity.adgroup.converter.AdGroupConverterUtils.convertGeo;
import static ru.yandex.direct.web.entity.adgroup.converter.AdGroupConverterUtils.convertMinusKeywords;
import static ru.yandex.direct.web.entity.adgroup.converter.AdGroupConverterUtils.convertPageBlocks;
import static ru.yandex.direct.web.entity.adgroup.converter.AdGroupConverterUtils.convertTags;
import static ru.yandex.direct.web.entity.adgroup.converter.RetargetingConverter.webCpmRetargetingsToCore;
import static ru.yandex.direct.web.entity.adgroup.converter.WebVideoGoalConverter.webVideoGoalsToCoreUsersSegments;
import static ru.yandex.direct.web.entity.banner.converter.CpmBannerConverter.webBannersToCoreCpmBanners;
import static ru.yandex.direct.web.entity.keyword.converter.KeywordConverter.webKeywordsToCoreKeywords;

public class CpmAdGroupConverter {

    private CpmAdGroupConverter() {
    }

    public static List<ComplexCpmAdGroup> webAdGroupsToCoreComplexCpmAdGroups(@Nullable List<WebCpmAdGroup> webAdGroups,
                                                                              long campaignId,
                                                                              CampaignType campaignType) {
        List<ComplexCpmAdGroup> complexAdGroups =
                mapList(webAdGroups, adGroup -> webAdGroupToCoreComplexCpmAdGroup(adGroup, campaignType));

        if (complexAdGroups != null) {
            StreamEx.of(complexAdGroups)
                    .nonNull()
                    .map(ComplexAdGroup::getAdGroup)
                    .nonNull()
                    .forEach(adGroup -> adGroup.withCampaignId(campaignId));
        }

        return complexAdGroups;
    }

    public static ComplexCpmAdGroup webAdGroupToCoreComplexCpmAdGroup(@Nullable WebCpmAdGroup webAdGroup,
                                                                      CampaignType campaignType) {
        AdGroup adGroup = webAdGroupToCoreAdGroup(webAdGroup, campaignType);
        return webAdGroup == null ? null : new ComplexCpmAdGroup()
                .withAdGroup(adGroup)
                .withBanners(webBannersToCoreCpmBanners(adGroup.getType(), webAdGroup.getBanners()))
                .withKeywords(webKeywordsToCoreKeywords(webAdGroup.getKeywords()))
                .withRetargetingConditions(RetargetingConverter
                        .webCpmRetargetingsToCoreRetargetingConditionsBase(webAdGroup.getRetargetings()))
                .withTargetInterests(webCpmRetargetingsToCore(webAdGroup.getRetargetings()))
                .withUsersSegments(webVideoGoalsToCoreUsersSegments(webAdGroup.getVideoGoals(), webAdGroup))
                .withComplexBidModifier(webAdGroupBidModifiersToCore(webAdGroup.getBidModifiers()));

    }

    private static AdGroup webAdGroupToCoreAdGroup(@Nullable WebCpmAdGroup webAdGroup, CampaignType campaignType) {
        if (webAdGroup == null) {
            return null;
        }

        AdGroupType adGroupType = AdGroupConverterUtils.extractCpmAdGroupType(webAdGroup, campaignType);
        checkNotNull(adGroupType, "ad group type should not be null");

        switch (adGroupType) {
            case CPM_BANNER:
                return webAdGroupToCoreCpmBannerAdGroup(webAdGroup);
            case CPM_VIDEO:
                return webAdGroupToCoreCpmVideoAdGroup(webAdGroup);
            case CPM_AUDIO:
                return webAdGroupToCoreCpmAudioAdGroup(webAdGroup);
            case CPM_OUTDOOR:
                return webAdGroupToCoreCpmOutdoorAdGroup(webAdGroup);
            case CPM_INDOOR:
                return webAdGroupToCoreCpmIndoorAdGroup(webAdGroup);
            case CPM_YNDX_FRONTPAGE:
                return webAdGroupToCoreCpmYndxFrontpageAdGroup(webAdGroup);
            case CPM_GEOPRODUCT:
                return webAdGroupToCoreCpmGeoproductAdGroup(webAdGroup);
            case CPM_GEO_PIN:
                return webAdGroupToCoreCpmGeoPinAdGroup(webAdGroup);
            default:
                throw new UnsupportedOperationException(format("Ad group of type %s is not supported.", adGroupType));
        }
    }

    private static AdGroup webAdGroupToCoreCpmBannerAdGroup(WebCpmAdGroup webAdGroup) {
        CpmBannerAdGroup adGroup = new CpmBannerAdGroup()
                .withType(AdGroupType.CPM_BANNER);

        if (!isEmpty(webAdGroup.getRetargetings())) {
            adGroup.withCriterionType(USER_PROFILE);
        } else {
            adGroup.withCriterionType(KEYWORD);
        }

        return adGroup
                .withId(webAdGroup.getId())
                .withName(webAdGroup.getName())
                .withMinusKeywords(convertMinusKeywords(webAdGroup))
                .withGeo(convertGeo(webAdGroup.getGeo()))
                .withTags(convertTags(webAdGroup.getTags()))
                .withProjectParamConditions(webAdGroup.getProjectParamConditions())
                .withPageGroupTags(webAdGroup.getPageGroupTags())
                .withTargetTags(webAdGroup.getTargetTags());
    }

    private static AdGroup webAdGroupToCoreCpmVideoAdGroup(WebCpmAdGroup webAdGroup) {
        return new CpmVideoAdGroup()
                .withType(AdGroupType.CPM_VIDEO)
                .withCriterionType(USER_PROFILE)
                .withId(webAdGroup.getId())
                .withName(webAdGroup.getName())
                .withMinusKeywords(convertMinusKeywords(webAdGroup))
                .withGeo(convertGeo(webAdGroup.getGeo()))
                .withTags(convertTags(webAdGroup.getTags()))
                .withProjectParamConditions(webAdGroup.getProjectParamConditions())
                .withPageGroupTags(webAdGroup.getPageGroupTags())
                .withTargetTags(webAdGroup.getTargetTags());
    }

    private static AdGroup webAdGroupToCoreCpmAudioAdGroup(WebCpmAdGroup webAdGroup) {
        return new CpmAudioAdGroup()
                .withType(AdGroupType.CPM_AUDIO)
                .withId(webAdGroup.getId())
                .withName(webAdGroup.getName())
                .withMinusKeywords(convertMinusKeywords(webAdGroup))
                .withGeo(convertGeo(webAdGroup.getGeo()))
                .withTags(convertTags(webAdGroup.getTags()))
                .withProjectParamConditions(webAdGroup.getProjectParamConditions())
                .withPageGroupTags(webAdGroup.getPageGroupTags())
                .withTargetTags(webAdGroup.getTargetTags());
    }

    private static AdGroup webAdGroupToCoreCpmOutdoorAdGroup(WebCpmAdGroup webAdGroup) {
        return new CpmOutdoorAdGroup()
                .withType(AdGroupType.CPM_OUTDOOR)
                .withId(webAdGroup.getId())
                .withName(webAdGroup.getName())
                .withTags(convertTags(webAdGroup.getTags()))
                .withPageBlocks(convertPageBlocks(webAdGroup.getPageBlocks()))
                .withPageGroupTags(webAdGroup.getPageGroupTags())
                .withTargetTags(webAdGroup.getTargetTags());
    }

    private static AdGroup webAdGroupToCoreCpmIndoorAdGroup(WebCpmAdGroup webAdGroup) {
        return new CpmIndoorAdGroup()
                .withType(AdGroupType.CPM_INDOOR)
                .withId(webAdGroup.getId())
                .withName(webAdGroup.getName())
                .withTags(convertTags(webAdGroup.getTags()))
                .withPageBlocks(convertPageBlocks(webAdGroup.getPageBlocks()))
                .withPageGroupTags(webAdGroup.getPageGroupTags())
                .withTargetTags(webAdGroup.getTargetTags());
    }

    private static AdGroup webAdGroupToCoreCpmYndxFrontpageAdGroup(WebCpmAdGroup webAdGroup) {
        return new CpmYndxFrontpageAdGroup()
                .withType(AdGroupType.CPM_YNDX_FRONTPAGE)
                .withId(webAdGroup.getId())
                .withName(webAdGroup.getName())
                .withGeo(convertGeo(webAdGroup.getGeo()))
                .withTags(convertTags(webAdGroup.getTags()))
                .withPageGroupTags(webAdGroup.getPageGroupTags())
                .withTargetTags(webAdGroup.getTargetTags());
    }

    private static AdGroup webAdGroupToCoreCpmGeoproductAdGroup(WebCpmAdGroup webAdGroup) {
        return new CpmGeoproductAdGroup().withType(AdGroupType.CPM_GEOPRODUCT)
                .withId(webAdGroup.getId())
                .withName(webAdGroup.getName())
                .withGeo(convertGeo(webAdGroup.getGeo()))
                .withTags(convertTags(webAdGroup.getTags()))
                .withPageGroupTags(webAdGroup.getPageGroupTags())
                .withTargetTags(webAdGroup.getTargetTags());
    }

    private static AdGroup webAdGroupToCoreCpmGeoPinAdGroup(WebCpmAdGroup webAdGroup) {
        return new CpmGeoPinAdGroup().withType(AdGroupType.CPM_GEO_PIN)
                .withId(webAdGroup.getId())
                .withName(webAdGroup.getName())
                .withGeo(convertGeo(webAdGroup.getGeo()))
                .withTags(convertTags(webAdGroup.getTags()))
                .withPageGroupTags(webAdGroup.getPageGroupTags())
                .withTargetTags(webAdGroup.getTargetTags());
    }

}
