package com.atlassian.stash.internal.locale;

import com.atlassian.bitbucket.auth.AuthenticationContext;
import com.atlassian.bitbucket.user.ApplicationUser;
import com.atlassian.stash.internal.user.InternalNormalUser;
import com.atlassian.stash.internal.user.InternalServiceUser;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import java.util.Locale;

import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.when;

public class DefaultLocaleServiceTest {

    @Rule
    public MockitoRule rule = MockitoJUnit.rule();

    @Mock
    private AuthenticationContext authenticationContext;

    private Locale contextLocale;

    private DefaultLocaleService localeService;

    private static InternalNormalUser normalUser(String name, Locale locale) {
        InternalNormalUser.Builder builder = new InternalNormalUser.Builder();
        builder.locale(locale);
        builder.name(name);
        return builder.build();
    }

    private static InternalServiceUser serviceUser() {
        return new InternalServiceUser.Builder().name("name").build();
    }

    @Before
    public void before() {
        localeService = new DefaultLocaleService(authenticationContext, () -> contextLocale);
    }

    @Test
    public void testGetLocaleReturnsLocaleFromUserWhenSet() {
        InternalNormalUser user = normalUser("jack", Locale.CHINESE);

        whenContextUserIs(user);
        whenContextLocaleIs(Locale.ENGLISH);

        assertThat(localeService.getLocale(), equalTo(Locale.CHINESE));
    }

    @Test
    public void testGetLocaleFromContextWhenUserHasNoLocale() {
        InternalNormalUser user = normalUser("jack", null);

        whenContextUserIs(user);
        whenContextLocaleIs(Locale.ENGLISH);

        assertThat(localeService.getLocale(), equalTo(Locale.ENGLISH));
    }

    @Test
    public void testGetLocaleFromContextWhenForAnonymousReturnsContextLocale() {
        whenContextUserIsAnonymous();
        whenContextLocaleIs(Locale.ENGLISH);

        assertThat(localeService.getLocale(), equalTo(Locale.ENGLISH));
    }

    @Test(expected = IllegalStateException.class)
    public void testGetLocaleFromContextThrowsErrorWhenNoLocaleAvailable() {
        InternalNormalUser user = normalUser("jack", null);

        whenContextUserIs(user);
        whenContextLocaleIs(null);

        localeService.getLocale();
    }

    @Test
    public void testGetLocaleFromContextWhenUserNotNormalUser() {
        ApplicationUser user = serviceUser();

        whenContextUserIs(user);
        whenContextLocaleIs(Locale.ENGLISH);

        assertThat(localeService.getLocale(), equalTo(Locale.ENGLISH));
    }

    private DefaultLocaleServiceTest whenContextLocaleIs(Locale locale) {
        contextLocale = locale;
        return this;
    }

    private DefaultLocaleServiceTest whenContextUserIsAnonymous() {
        when(authenticationContext.getCurrentUser()).thenReturn(null);
        return this;
    }

    private DefaultLocaleServiceTest whenContextUserIs(ApplicationUser user) {
        when(authenticationContext.getCurrentUser()).thenReturn(user);
        return this;
    }
}