package com.atlassian.stash.internal.notification.usersettings;

import com.atlassian.bitbucket.server.ApplicationPropertiesService;
import com.atlassian.bitbucket.user.ApplicationUser;
import com.atlassian.event.api.EventPublisher;
import com.atlassian.sal.api.user.UserKey;
import com.atlassian.sal.api.usersettings.UserSettings;
import com.atlassian.sal.api.usersettings.UserSettingsService;
import com.atlassian.stash.internal.notification.event.NotificationSendModePreferenceChangeEvent;

import javax.annotation.Nonnull;
import java.util.Objects;

import static com.atlassian.stash.internal.notification.NotificationConstants.PROP_DEFAULT_SEND_MODE;
import static com.google.common.base.Preconditions.checkNotNull;

public class DefaultUserNotificationSettingsService implements UserNotificationSettingsService {

    private final EventPublisher eventPublisher;
    private final UserSettingsService userSettingsService;
    private final SendMode defaultSendMode;

    public DefaultUserNotificationSettingsService(EventPublisher eventPublisher,
                                                  ApplicationPropertiesService propertiesService,
                                                  UserSettingsService userSettingsService) {
        this.eventPublisher = eventPublisher;
        this.userSettingsService = userSettingsService;

        defaultSendMode = SendMode.fromString(propertiesService.getPluginProperty(PROP_DEFAULT_SEND_MODE, SendMode.BATCHED.name()));
    }

    @Override
    @Nonnull
    public UserNotificationSettings getSettingsForUser(@Nonnull ApplicationUser user) {
        UserSettings settings = userSettingsService.getUserSettings(getUserKeyForUser(user));

        return new UserNotificationSettings.Builder(settings, defaultSendMode).build();
    }

    @Override
    public void updateSettingsForUser(@Nonnull ApplicationUser user, @Nonnull UserNotificationSettings newSettings) {
        userSettingsService.updateUserSettings(getUserKeyForUser(user), (builder) -> {
            // Building the UserSettingsBuilder provides the _existing_ settings for the user
            UserNotificationSettings oldSettings = new UserNotificationSettings.Builder(builder.build(), defaultSendMode).build();

            // Update the settings. The new values may be the same as the old ones, or they may be different
            newSettings.applyTo(builder);
            // After updating, publish the preference change event _if preferences were changed_
            maybePublishPreferenceChange(user, oldSettings, newSettings);

            return builder.build();
        });
    }

    /**
     * Optimisation to avoid a database lookup via UserProfile
     */
    private UserKey getUserKeyForUser(ApplicationUser user) {
        return UserKey.fromLong(checkNotNull(user, "user").getId());
    }

    private void maybePublishPreferenceChange(ApplicationUser user, UserNotificationSettings oldSettings,
                                              UserNotificationSettings newSettings) {
        if (!(newSettings.getSendMode() == null || //null means no change was made
                Objects.equals(oldSettings.getSendMode(), newSettings.getSendMode()))) {
            eventPublisher.publish(new NotificationSendModePreferenceChangeEvent(this,
                    user, newSettings.getSendMode(), defaultSendMode));
        }
    }
}
