package ru.yandex.direct.api.v5.entity.clients.service;

import java.util.Map;

import com.google.common.collect.ImmutableMap;
import com.yandex.direct.api.v5.general.YesNoEnum;
import com.yandex.direct.api.v5.generalclients.ClientSettingUpdateEnum;
import com.yandex.direct.api.v5.generalclients.ClientSettingUpdateItem;
import com.yandex.direct.api.v5.generalclients.ClientUpdateItem;
import com.yandex.direct.api.v5.generalclients.EmailSubscriptionEnum;
import com.yandex.direct.api.v5.generalclients.EmailSubscriptionItem;
import com.yandex.direct.api.v5.generalclients.NotificationUpdate;
import one.util.streamex.StreamEx;

import ru.yandex.direct.api.v5.converter.PropertyConverter;
import ru.yandex.direct.api.v5.converter.PropertyConverterFactory;
import ru.yandex.direct.core.entity.client.model.Client;
import ru.yandex.direct.core.entity.user.model.User;
import ru.yandex.direct.i18n.Language;
import ru.yandex.direct.model.ModelChanges;

import static com.yandex.direct.api.v5.generalclients.ClientSettingUpdateEnum.CORRECT_TYPOS_AUTOMATICALLY;
import static com.yandex.direct.api.v5.generalclients.ClientSettingUpdateEnum.DISPLAY_STORE_RATING;
import static com.yandex.direct.api.v5.generalclients.EmailSubscriptionEnum.RECEIVE_RECOMMENDATIONS;
import static com.yandex.direct.api.v5.generalclients.EmailSubscriptionEnum.TRACK_MANAGED_CAMPAIGNS;
import static com.yandex.direct.api.v5.generalclients.EmailSubscriptionEnum.TRACK_POSITION_CHANGES;


public class UpdateConverter {
    private static final Map<EmailSubscriptionEnum, PropertyConverter<User, YesNoEnum, Boolean>>
            EMAIL_SUBSCRIPTIONS_PROPS =
            ImmutableMap.of(
                    RECEIVE_RECOMMENDATIONS, PropertyConverterFactory.yesToTrue(User.SEND_NEWS),
                    TRACK_MANAGED_CAMPAIGNS, PropertyConverterFactory.yesToTrue(User.SEND_ACC_NEWS),
                    TRACK_POSITION_CHANGES, PropertyConverterFactory.yesToTrue(User.SEND_WARN)
            );

    private static final Map<ClientSettingUpdateEnum, PropertyConverter<Client, YesNoEnum, Boolean>> SETTINGS_PROPS =
            ImmutableMap.of(
                    DISPLAY_STORE_RATING, PropertyConverterFactory.yesToFalse(Client.HIDE_MARKET_RATING),
                    CORRECT_TYPOS_AUTOMATICALLY, PropertyConverterFactory.yesToFalse(Client.NO_TEXT_AUTOCORRECTION)
            );

    private UpdateConverter() {
    }

    static UserClientChanges convertToChanges(ClientUpdateItem updateItem, Long uid, Long clientId) {
        ModelChanges<User> userChanges = new ModelChanges<>(uid, User.class);
        processUserChanges(userChanges, updateItem);

        ModelChanges<Client> clientChanges = new ModelChanges<>(clientId, Client.class);
        processClientChanges(clientChanges, updateItem);

        return new UserClientChanges(userChanges, clientChanges);
    }

    public static void processUserChanges(ModelChanges<User> userChanges, ClientUpdateItem updateItem) {
        userChanges.processNotNull(updateItem.getClientInfo(), User.FIO);
        userChanges.processNotNull(updateItem.getPhone(), User.PHONE);

        NotificationUpdate notification = updateItem.getNotification();
        if (notification != null) {
            userChanges.processNotNull(notification.getEmail(), User.EMAIL);

            StreamEx.of(notification.getEmailSubscriptions())
                    .mapToEntry(EmailSubscriptionItem::getOption, EmailSubscriptionItem::getValue)
                    .forKeyValue((option, value) -> {
                        PropertyConverter<User, YesNoEnum, Boolean> propertyConverter =
                                EMAIL_SUBSCRIPTIONS_PROPS.get(option);
                        userChanges.process(propertyConverter.apply(value), propertyConverter.getProperty());
                    });
            if (notification.getLang() != null) {
                userChanges.process(Language.fromLangString(notification.getLang().value().toLowerCase()), User.LANG);
            }
        }
    }

    public static void processClientChanges(ModelChanges<Client> clientChanges, ClientUpdateItem updateItem) {
        StreamEx.of(updateItem.getSettings())
                .mapToEntry(ClientSettingUpdateItem::getOption, ClientSettingUpdateItem::getValue)
                .forKeyValue((option, value) -> {
                    PropertyConverter<Client, YesNoEnum, Boolean> propertyConverter = SETTINGS_PROPS.get(option);
                    clientChanges.process(propertyConverter.apply(value), propertyConverter.getProperty());
                });
    }
}
