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

import java.util.List;

import com.yandex.direct.api.v5.general.AdGroupTypesEnum;
import com.yandex.direct.api.v5.general.YesNoEnum;
import com.yandex.direct.api.v5.retargetinglists.AvailableForTargetsInAdGroupTypesArray;
import com.yandex.direct.api.v5.retargetinglists.ObjectFactory;
import com.yandex.direct.api.v5.retargetinglists.RetargetingListGetItem;
import com.yandex.direct.api.v5.retargetinglists.RetargetingListRuleArgumentItem;
import com.yandex.direct.api.v5.retargetinglists.RetargetingListRuleItem;
import com.yandex.direct.api.v5.retargetinglists.RetargetingListRuleOperatorEnum;
import com.yandex.direct.api.v5.retargetinglists.RetargetingListScopeEnum;
import com.yandex.direct.api.v5.retargetinglists.RetargetingListTypeEnum;
import org.springframework.stereotype.Component;

import ru.yandex.direct.core.entity.retargeting.container.AllowedRetargetingComponentsInUserProfile;
import ru.yandex.direct.core.entity.retargeting.model.ConditionType;
import ru.yandex.direct.core.entity.retargeting.model.CryptaInterestType;
import ru.yandex.direct.core.entity.retargeting.model.RetargetingCondition;
import ru.yandex.direct.core.entity.retargeting.model.RetargetingConditionGoal;
import ru.yandex.direct.core.entity.retargeting.model.Rule;
import ru.yandex.direct.core.entity.retargeting.model.RuleType;

import static com.yandex.direct.api.v5.general.AdGroupTypesEnum.CPM_BANNER_AD_GROUP;
import static com.yandex.direct.api.v5.general.AdGroupTypesEnum.CPM_VIDEO_AD_GROUP;
import static com.yandex.direct.api.v5.general.AdGroupTypesEnum.MOBILE_APP_AD_GROUP;
import static com.yandex.direct.api.v5.general.AdGroupTypesEnum.TEXT_AD_GROUP;
import static com.yandex.direct.api.v5.retargetinglists.RetargetingListTypeEnum.AUDIENCE;
import static com.yandex.direct.api.v5.retargetinglists.RetargetingListTypeEnum.RETARGETING;
import static java.util.Arrays.asList;
import static ru.yandex.direct.api.v5.entity.retargetinglists.converter.GoalInterestsTypeConverter.getExternalId;
import static ru.yandex.direct.core.entity.retargeting.model.ConditionType.interests;
import static ru.yandex.direct.core.entity.retargeting.service.common.GoalUtilsService.isRetargetingConditionAllowedForTextAdGroup;
import static ru.yandex.direct.utils.CommonUtils.ifNotNull;
import static ru.yandex.direct.utils.CommonUtils.nvl;
import static ru.yandex.direct.utils.FunctionalUtils.mapList;

@Component
public class RetargetingConditionConverter {
    private static final ObjectFactory FACTORY = new ObjectFactory();

    public RetargetingListGetItem convert(RetargetingCondition retCondition,
            AllowedRetargetingComponentsInUserProfile allowedRetargetingComponentsInUserProfile) {
        RetargetingListGetItem item = new RetargetingListGetItem().
                withId(retCondition.getId()).
                withName(retCondition.getName()).
                withDescription(FACTORY.createRetargetingListBaseDescription(
                        nvl(retCondition.getDescription(), "").equals("") ? null : retCondition.getDescription())).
                withIsAvailable(retCondition.getAvailable() ? YesNoEnum.YES : YesNoEnum.NO).
                withType(convertConditionType(retCondition.getType())).
                withRules(convertRules(retCondition.getRules())).
                withScope(getScope(retCondition));

        List<AdGroupTypesEnum> availableAdGroupTypes = getAvailableAdGroupTypes(item.getScope(), retCondition,
                allowedRetargetingComponentsInUserProfile);

        return item
                .withAvailableForTargetsInAdGroupTypes(
                        FACTORY.createRetargetingListGetItemAvailableForTargetsInAdGroupTypes(
                        ifNotNull(availableAdGroupTypes,
                                types -> new AvailableForTargetsInAdGroupTypesArray().withItems(types))));
    }

    private RetargetingListTypeEnum convertConditionType(ConditionType type) {

        if (type == null) {
            return null;
        }

        switch (type) {
            case metrika_goals:
                return RETARGETING;
            case interests:
                return AUDIENCE;
            default:
                throw new IllegalArgumentException("RetargetingListTypeEnum: " + type);
        }
    }

    private List<RetargetingListRuleItem> convertRules(List<Rule> rules) {
        return mapList(rules, r -> new RetargetingListRuleItem().
                withArguments(convertGoals(r.getGoals(), r.getInterestType())).
                withOperator(convertRuleType(r.getType())));
    }

    private List<RetargetingListRuleArgumentItem> convertGoals(List<? extends RetargetingConditionGoal> arguments,
                                                               CryptaInterestType interestType) {
        return mapList(arguments, arg -> new RetargetingListRuleArgumentItem()
                .withExternalId(getExternalId(arg.getId(), interestType))
                .withMembershipLifeSpan(arg.getTime()));
    }

    private RetargetingListRuleOperatorEnum convertRuleType(RuleType type) {
        switch (type) {
            case ALL:
                return RetargetingListRuleOperatorEnum.ALL;
            case OR:
                return RetargetingListRuleOperatorEnum.ANY;
            case NOT:
                return RetargetingListRuleOperatorEnum.NONE;
            default:
                throw new IllegalStateException("unknown operator type: " + type.toString());
        }
    }

    private RetargetingListScopeEnum getScope(RetargetingCondition retCondition) {
        if (retCondition.getType() == interests) {
            return RetargetingListScopeEnum.FOR_TARGETS_ONLY;
        } else if (retCondition.getNegative()) {
            return RetargetingListScopeEnum.FOR_ADJUSTMENTS_ONLY;
        } else {
            return RetargetingListScopeEnum.FOR_TARGETS_AND_ADJUSTMENTS;
        }
    }

    private List<AdGroupTypesEnum> getAvailableAdGroupTypes(RetargetingListScopeEnum scope,
            RetargetingCondition retCondition,
            AllowedRetargetingComponentsInUserProfile allowedRetargetingComponentsInUserProfile) {

        if (scope == RetargetingListScopeEnum.FOR_TARGETS_AND_ADJUSTMENTS) {
            return asList(TEXT_AD_GROUP, MOBILE_APP_AD_GROUP);
        } else if (scope == RetargetingListScopeEnum.FOR_TARGETS_ONLY) {
            if (isRetargetingConditionAllowedForTextAdGroup(
                    retCondition,
                    allowedRetargetingComponentsInUserProfile)) {
                return asList(TEXT_AD_GROUP, CPM_BANNER_AD_GROUP, CPM_VIDEO_AD_GROUP);
            } else {
                return asList(CPM_BANNER_AD_GROUP, CPM_VIDEO_AD_GROUP);
            }
        } else {
            return null;
        }
    }
}
