package ru.yandex.wmconsole.servantlet.messages.options;

import java.util.Map;

import org.springframework.beans.factory.annotation.Required;

import ru.yandex.common.framework.core.ServRequest;
import ru.yandex.common.framework.core.ServResponse;
import ru.yandex.wmconsole.data.NotificationChannelEnum;
import ru.yandex.wmconsole.data.NotificationTypeEnum;
import ru.yandex.wmconsole.data.UserNotificationOptions;
import ru.yandex.wmconsole.data.info.UserOptionsInfo;
import ru.yandex.wmconsole.service.ForeignServicesService;
import ru.yandex.wmconsole.service.NotificationOptionsService;
import ru.yandex.wmconsole.service.UserOptionsService;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.error.UserException;
import ru.yandex.wmtools.common.error.UserProblem;
import ru.yandex.wmtools.common.servantlet.AuthenticationServantlet;

/**
 * @author Andrey Mima (amima@yandex-team.ru)
 */
public class NotificationOptionsChangeServantlet extends AuthenticationServantlet {
    private static final String EMPTY = "";
    private static final String PARAM_PERCENT = "percent";
    private static final String PREFIX_MESSAGE = "message_";
    private static final String PREFIX_SMS = "sms_";
    private static final String PREFIX_EMAIL = "email_";

    private NotificationOptionsService notificationOptionsService;
    private UserOptionsService userOptionsService;
    private ForeignServicesService foreignServicesService;

    @Override
    public void doProcess(ServRequest req, ServResponse res, long userId) throws UserException, InternalException {
        checkService(notificationOptionsService, NotificationOptionsService.class);
        checkService(userOptionsService, UserOptionsService.class);
        checkService(foreignServicesService, ForeignServicesService.class);
        String percent = req.getParam(PARAM_PERCENT, true);
        changeOptions(userId, req);

        if (percent != null && !EMPTY.equals(percent)) {
            savePercent(userId, percent);
        }
    }

    private void changeOptions(long userId, ServRequest req)
            throws UserException, InternalException {
        UserNotificationOptions userNotificationOptions = new UserNotificationOptions(userId);
        parseNotificationParameters(req, userNotificationOptions);
        notificationOptionsService.updateUserNotificationOptions(userNotificationOptions);
    }

    private void parseNotificationParameters(ServRequest req, UserNotificationOptions userNotificationOptions) throws InternalException {
        //noinspection unchecked
        Map<String, String> params = req.getParams();

        for (Map.Entry<String, String> param : params.entrySet()) {
            String paramName = param.getKey();

            parseNotificationOption(paramName, PREFIX_SMS, NotificationChannelEnum.SMS, userNotificationOptions);
            parseNotificationOption(paramName, PREFIX_EMAIL, NotificationChannelEnum.EMAIL, userNotificationOptions);
            parseNotificationOption(paramName, PREFIX_MESSAGE, NotificationChannelEnum.MESSAGE, userNotificationOptions);
        }
    }

    private void parseNotificationOption(String paramName, String prefix, NotificationChannelEnum channel,
                                         UserNotificationOptions userNotificationOptions) throws InternalException {
        if (paramName.startsWith(prefix)) {
            try {
                final Integer typeInteger = Integer.parseInt(paramName.substring(prefix.length()));
                if (typeInteger <= NotificationTypeEnum.MAX_VALUE) {
                    NotificationTypeEnum type = NotificationTypeEnum.R.fromValueOrNull(typeInteger);
                    userNotificationOptions.addNotificationOption(type, channel);
                } else {
                    if (foreignServicesService.isActiveService(typeInteger)) {
                        userNotificationOptions.addNotificationOption(typeInteger, channel);
                    }
                }
            } catch (NumberFormatException e) {
                // Ignore
            }
        }
    }

    private void savePercent(long userId, String percentString) throws InternalException, UserException {
        try {
            Integer percent = Integer.valueOf(percentString);
            if (percent < 0) {
                throw new UserException(UserProblem.ILLEGAL_PARAM_VALUE, "Percent value less than zero", PARAM_PERCENT, percentString);
            }
            UserOptionsInfo userOptions = userOptionsService.getUserOptions(userId);
            UserOptionsInfo newOptions = userOptions.replacePercent(percent);
            userOptionsService.updateUserOptions(newOptions);
        } catch (NumberFormatException e) {
            throw new UserException(UserProblem.ILLEGAL_VALUE_TYPE, "Invalid percent value", PARAM_PERCENT, percentString);
        }
    }

    @Required
    public void setNotificationOptionsService(NotificationOptionsService notificationOptionsService) {
        this.notificationOptionsService = notificationOptionsService;
    }

    @Required
    public void setUserOptionsService(UserOptionsService userOptionsService) {
        this.userOptionsService = userOptionsService;
    }

    @Required
    public void setForeignServicesService(ForeignServicesService foreignServicesService) {
        this.foreignServicesService = foreignServicesService;
    }
}
