package com.atlassian.bitbucket.internal.mirroring.upstream;

import com.atlassian.bitbucket.auth.AuthenticationContext;
import com.atlassian.bitbucket.mirroring.upstream.MirrorServer;
import com.atlassian.bitbucket.mirroring.upstream.MirrorService;
import com.atlassian.bitbucket.permission.PermissionValidationService;
import com.atlassian.bitbucket.user.ApplicationUser;
import com.atlassian.fugue.Option;
import com.atlassian.sal.api.user.UserKey;
import com.atlassian.sal.api.usersettings.UserSettings;
import com.atlassian.sal.api.usersettings.UserSettingsService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Optional;

import static com.atlassian.bitbucket.internal.mirroring.upstream.UpstreamConstants.USER_SETTING_PREFERRED_MIRROR_KEY;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.*;


@RunWith(MockitoJUnitRunner.class)
public class DefaultMirroringUserSettingsServiceTest {

    @Mock
    private AuthenticationContext authenticationContext;
    @Mock
    private MirrorService mirrorService;
    @Mock
    private PermissionValidationService permissionValidationService;
    @Mock
    private SmartMirroringFeature mirroringFeature;
    @Mock
    private UserSettingsService userSettingsService;
    @Mock
    private ApplicationUser user;

    @InjectMocks
    DefaultMirroringUserSettingsService service;

    @Before
    public void setup() {
        when(user.getId()).thenReturn(42);
        when(authenticationContext.getCurrentUser()).thenReturn(user);
        when(mirroringFeature.isEnabled()).thenReturn(true);
    }

    @Test
    public void testGetPreferredMirror() {
        String id = "paulaner-hell";
        mockUserSettings(USER_SETTING_PREFERRED_MIRROR_KEY, Option.some(id));
        MirrorServer mockMirror = mock(MirrorServer.class);
        when(mockMirror.getId()).thenReturn(id);
        when(mirrorService.getById(eq(id))).thenReturn(mockMirror);

        Optional<MirrorServer> mirror = service.getPreferredMirror();

        assertNotNull(mirror);
        assertEquals(mirror.get().getId(), id);
    }

    @Test
    public void testGetPreferredMirrorNotSet() {
        mockUserSettings(USER_SETTING_PREFERRED_MIRROR_KEY, Option.none());

        Optional<MirrorServer> mirror = service.getPreferredMirror();

        assertNotNull(mirror);
        assertFalse(mirror.isPresent());
    }

    @Test
    public void testSetPreferredMirror() {
        UserKey key = UserKey.fromLong(user.getId());
        MirrorServer mirror = mock(MirrorServer.class);
        service.setPreferredMirror(mirror);

        verify(userSettingsService).updateUserSettings(eq(key), any());
        verifyNoMoreInteractions(userSettingsService);
    }

    @Test
    public void testGetPreferredMirrorSetMirroringDisabled() {
        mockUserSettings(USER_SETTING_PREFERRED_MIRROR_KEY, Option.some("id"));
        when(mirroringFeature.isEnabled()).thenReturn(false);

        Optional<MirrorServer> mirror = service.getPreferredMirror();

        assertNotNull(mirror);
        assertFalse(mirror.isPresent());
    }


    private void mockUserSettings(String key, Option<String> value) {
        UserSettings settings = mock(UserSettings.class);
        when(settings.getString(eq(key)))
                .thenReturn(value);
        when(userSettingsService.getUserSettings(isA(UserKey.class))).thenReturn(settings);
    }
}
