package ru.yandex.wmconsole.service;

import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import ru.yandex.wmconsole.data.LanguageEnum;
import ru.yandex.wmconsole.data.info.UserOptionsInfo;
import ru.yandex.wmconsole.data.partition.WMCPartition;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.service.AbstractDbService;
import ru.yandex.wmtools.common.util.SqlUtil;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * @author Andrey Mima (amima@yandex-team.ru)
 */
public class UserOptionsService extends AbstractDbService {
    public static final Integer DEFAULT_ERRORS_GROW = 50;
    public static final boolean DEFAULT_USE_GLOBAL_ERROR_OPTIONS = true;

    private static final String EMPTY_EMAIL = "";
    private static final Long EMPTY_PHONE = (long) 0;

    private static final String FIELD_USER_ID = "user_id";
    private static final String FIELD_EMAIL = "email";
    private static final String FIELD_PHONE = "phone";
    private static final String FIELD_ERRORS_GROW = "errors_grow";
    private static final String FIELD_EMAIL_LANG = "email_lang";
    private static final String FIELD_USE_GLOBAL_ERROR_OPTIONS = "use_global_error_options";

    private static final String REPLACRE_OPTIONS_FOR_USER_QUERY =
            "REPLACE " +
                    "INTO " +
                    "tbl_user_options (user_id, email, phone, errors_grow, email_lang, use_global_error_options) " +
                    "VALUES " +
                    "(?, ?, ?, ?, ?, ?)";

    private static final String SELECT_OPTIONS_FOR_USER_QUERY =
            "SELECT " +
                    "user_id, email, phone, errors_grow, email_lang, use_global_error_options " +
                    "FROM " +
                    "tbl_user_options " +
                    "WHERE " +
                    "user_id = ?";

    private static final ParameterizedRowMapper<UserOptionsInfo> USER_OPTIONS_MAPPER =
            new ParameterizedRowMapper<UserOptionsInfo>() {
                @Override
                public UserOptionsInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
                    Long userId = rs.getLong(FIELD_USER_ID);
                    String email = rs.getString(FIELD_EMAIL);
                    Long phone = rs.getLong(FIELD_PHONE);
                    Integer errorsGrow = rs.getInt(FIELD_ERRORS_GROW);
                    final Integer emailLangId = SqlUtil.getIntNullable(rs, FIELD_EMAIL_LANG);
                    LanguageEnum emailLanguage = emailLangId != null ? LanguageEnum.R.fromValueOrNull(emailLangId) : null;
                    boolean useGlobalErrorOptions = rs.getBoolean(FIELD_USE_GLOBAL_ERROR_OPTIONS);
                    return new UserOptionsInfo(userId, email, emailLanguage, phone, errorsGrow, useGlobalErrorOptions);
                }
            };

    public void updateUserEmail(long userId, String email) throws InternalException {
        getJdbcTemplate(WMCPartition.nullPartition())
                .update("UPDATE tbl_user_options SET email = ? where user_id = ?",
                        email, userId);
    }

    public void updateUserOptions(UserOptionsInfo userOptionsInfo) throws InternalException {
        final Integer emailLang;
        if (userOptionsInfo.getEmailLanguage() != null) {
            emailLang = userOptionsInfo.getEmailLanguage().getId();
        } else {
            emailLang = null;
        }

        getJdbcTemplate(WMCPartition.nullPartition()).update(REPLACRE_OPTIONS_FOR_USER_QUERY,
                userOptionsInfo.getUserId(),
                userOptionsInfo.getEmail(),
                userOptionsInfo.getPhone(),
                userOptionsInfo.getErrorsGrow(),
                emailLang,
                userOptionsInfo.isUseGlobalErrorOptions()
        );
    }

    public UserOptionsInfo getUserOptions(Long userId) throws InternalException {
        UserOptionsInfo userOptions = getJdbcTemplate(WMCPartition.nullPartition()).safeQueryForObject(
                SELECT_OPTIONS_FOR_USER_QUERY,
                USER_OPTIONS_MAPPER,
                userId
        );

        if (userOptions == null) {
            return new UserOptionsInfo(
                    userId, EMPTY_EMAIL, null, EMPTY_PHONE, DEFAULT_ERRORS_GROW, DEFAULT_USE_GLOBAL_ERROR_OPTIONS);
        } else {
            return userOptions;
        }
    }

    public List<ExportUserOptions> exportUserOptions(long fromUserId, int limit) throws InternalException {
        return getJdbcTemplate(WMCPartition.nullPartition())
                .query("SELECT " +
                                "   u.user_id AS user_id, " +
                                "   uo.email AS email, " +
                                "   SUM(IF(notification_channel = 0, 1, 0)) AS allow_message, " +
                                "   SUM(IF(notification_channel = 2, 1, 0)) AS allow_email " +
                                "   FROM tbl_users u " +
                                "   LEFT JOIN tbl_user_options uo USING(user_id) " +
                                "   LEFT JOIN tbl_user_notification_options uno ON u.user_id = uno.user_id AND uno.notification_type = 3 " +
                                "   WHERE u.user_id > ? " +
                                "   GROUP BY user_id " +
                                "   ORDER BY user_id ASC " +
                                "   LIMIT ?;",
                        new ParameterizedRowMapper<ExportUserOptions>() {
                            @Override
                            public ExportUserOptions mapRow(ResultSet resultSet, int i) throws SQLException {
                                return new ExportUserOptions(
                                        resultSet.getLong("user_id"),
                                        resultSet.getString("email"),
                                        resultSet.getBoolean("allow_message"),
                                        resultSet.getBoolean("allow_email")
                                );
                            }
                        }, fromUserId, limit);
    }

    public static class ExportUserOptions {
        private final long userId;
        private final String email;
        private final boolean allowSearchUpdateMessage;
        private final boolean allowSearchUpdateEmail;

        public ExportUserOptions(long userId, String email, boolean allowSearchUpdateMessage, boolean allowSearchUpdateEmail) {
            this.userId = userId;
            this.email = StringUtils.isEmpty(email) ? null : email;
            this.allowSearchUpdateMessage = allowSearchUpdateMessage;
            this.allowSearchUpdateEmail = allowSearchUpdateEmail;
        }

        public long getUserId() {
            return userId;
        }

        public boolean isAllowSearchUpdateMessage() {
            return allowSearchUpdateMessage;
        }

        public boolean isAllowSearchUpdateEmail() {
            return allowSearchUpdateEmail;
        }

        public String getEmail() {
            return email;
        }
    }
}
