package com.atlassian.stash.internal.server;

import com.atlassian.bitbucket.license.LicenseService;
import com.atlassian.bitbucket.server.Feature;
import com.atlassian.bitbucket.server.SimpleFeature;
import com.atlassian.bitbucket.server.StandardFeature;
import com.atlassian.extras.api.bitbucket.BitbucketServerLicense;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Properties;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class PropertyFeatureManagerTest {

    @Mock
    private BitbucketServerLicense license;
    @Mock
    private LicenseService licenseService;
    private PropertyFeatureManager manager;
    private Feature pluginFeature1;
    private Feature pluginDcFeature2;
    private Feature pluginDcFeature3;
    private Feature undefinedDcFeature;

    @Before
    public void setUp() throws Exception {
        Properties applicationProperties = new Properties();
        applicationProperties.setProperty(PropertyFeatureManager.PROP_PREFIX + StandardFeature.AUTH_CAPTCHA.getKey(), Boolean.toString(true));
        applicationProperties.setProperty(PropertyFeatureManager.PROP_PREFIX + StandardFeature.PUBLIC_ACCESS.getKey(), Boolean.toString(false));
        applicationProperties.setProperty("some.random.property", Boolean.toString(false));
        applicationProperties.setProperty("some.other.random.property", "blah");
        applicationProperties.setProperty(PropertyFeatureManager.PROP_PREFIX + "plugin1", Boolean.toString(true));
        applicationProperties.setProperty(PropertyFeatureManager.PROP_PREFIX + "plugin2", Boolean.toString(false));
        applicationProperties.setProperty(PropertyFeatureManager.PROP_PREFIX + "plugin3", Boolean.toString(true));

        when(licenseService.get()).thenReturn(license);

        manager = new PropertyFeatureManager(applicationProperties);
        manager.setLicenseService(licenseService);

        pluginFeature1 = new SimpleFeature.Builder("plugin1").build();
        pluginDcFeature2 = new SimpleFeature.Builder("plugin2").dataCenter(true).build();
        pluginDcFeature3 = new SimpleFeature.Builder("plugin3").dataCenter(true).build();
        undefinedDcFeature = new SimpleFeature.Builder("undefined").dataCenter(true).build();
    }

    @Test
    public void testIsAvailableDataCenter() {
        when(license.isClusteringEnabled()).thenReturn(true);

        assertTrue("Captcha should be available", manager.isAvailable(StandardFeature.AUTH_CAPTCHA));
        assertTrue("Forks should be available even when disabled", manager.isAvailable(StandardFeature.FORKS));
        assertTrue("Public access should be available even when disabled", manager.isAvailable(StandardFeature.PUBLIC_ACCESS));

        assertTrue("Plugin provided features should be available", manager.isAvailable(pluginFeature1));

        // data center features
        assertTrue("Mirroring should be available on a Data Center instance", manager.isAvailable(StandardFeature.SMART_MIRRORS));
        assertTrue("Plugin provided DC feature should be available on a DC instance", manager.isAvailable(pluginDcFeature2));
    }

    @Test
    public void testIsAvailableNonDataCenter() {
        assertTrue("Captcha should be available", manager.isAvailable(StandardFeature.AUTH_CAPTCHA));
        assertTrue("Forks should be available even when disabled", manager.isAvailable(StandardFeature.FORKS));
        assertTrue("Public access should be available even when disabled", manager.isAvailable(StandardFeature.PUBLIC_ACCESS));

        assertTrue("Plugin provided features should be available", manager.isAvailable(pluginFeature1));

        // data center features
        assertFalse("Mirroring is a Data Center feature and should not be available", manager.isAvailable(StandardFeature.SMART_MIRRORS));
        assertFalse("Plugin provided DC feature should not be available", manager.isAvailable(pluginDcFeature2));
    }

    @Test
    public void testIsEnabledDataCenter() {
        when(license.isClusteringEnabled()).thenReturn(true);

        assertTrue("Captcha should be explicitly enabled", manager.isEnabled(StandardFeature.AUTH_CAPTCHA));
        assertFalse("Forks should be implicitly disabled", manager.isEnabled(StandardFeature.FORKS));
        assertFalse("Public access should be explicitly disabled", manager.isEnabled(StandardFeature.PUBLIC_ACCESS));

        assertTrue("Plugin1 should be explicitly enabled", manager.isEnabled(pluginFeature1));
        assertFalse("Plugin2 should be explicitly disabled", manager.isEnabled(pluginDcFeature2));
        assertTrue("Plugin3 should be explicitly enabled", manager.isEnabled(pluginDcFeature3));
        assertFalse("Undefined should default to disabled", manager.isEnabled(undefinedDcFeature));
    }

    @Test
    public void testIsEnabledNonDataCenter() {
        assertTrue("Captcha should be explicitly enabled", manager.isEnabled(StandardFeature.AUTH_CAPTCHA));
        assertFalse("Forks should be implicitly disabled", manager.isEnabled(StandardFeature.FORKS));
        assertFalse("Public access should be explicitly disabled", manager.isEnabled(StandardFeature.PUBLIC_ACCESS));

        assertTrue("Plugin1 should be explicitly enabled", manager.isEnabled(pluginFeature1));
        assertFalse("Plugin2 should be explicitly disabled", manager.isEnabled(pluginDcFeature2));
        assertFalse("Plugin3 should be disabled because it requires DC", manager.isEnabled(pluginDcFeature3));
        assertFalse("Undefined should be disabled because it requires DC", manager.isEnabled(undefinedDcFeature));
    }

    @Test
    public void testIsEnabledWithDefaultDataCenter() {
        when(license.isClusteringEnabled()).thenReturn(true);

        assertTrue("Captcha should be explicitly enabled", manager.isEnabled(StandardFeature.AUTH_CAPTCHA, false));
        assertFalse("Forks should be implicitly disabled", manager.isEnabled(StandardFeature.FORKS, true));
        assertFalse("Public access should be explicitly disabled", manager.isEnabled(StandardFeature.PUBLIC_ACCESS, true));

        assertTrue("Plugin1 should be explicitly enabled", manager.isEnabled(pluginFeature1, false));
        assertFalse("Plugin2 should be explicitly disabled", manager.isEnabled(pluginDcFeature2, true));
        assertTrue("Plugin3 should be explicitly enabled", manager.isEnabled(pluginDcFeature3, false));

        assertFalse("Undefined should default to disabled", manager.isEnabled(undefinedDcFeature, false));
        assertTrue("Undefined should default to enabled", manager.isEnabled(undefinedDcFeature, true));
    }

    @Test
    public void testIsEnabledWithDefaultNonDataCenter() {
        assertTrue("Captcha should be explicitly enabled", manager.isEnabled(StandardFeature.AUTH_CAPTCHA, false));
        assertFalse("Forks should be implicitly disabled", manager.isEnabled(StandardFeature.FORKS, true));
        assertFalse("Public access should be explicitly disabled", manager.isEnabled(StandardFeature.PUBLIC_ACCESS, true));

        assertTrue("Plugin1 should be explicitly enabled", manager.isEnabled(pluginFeature1, false));
        assertFalse("Plugin2 should be explicitly disabled", manager.isEnabled(pluginDcFeature2, true));
        assertFalse("Plugin3 should be disabled because it requires DC", manager.isEnabled(pluginDcFeature3, true));

        assertFalse("Undefined should be disabled because it requires DC", manager.isEnabled(undefinedDcFeature, false));
        assertFalse("Undefined should be disabled because it requires DC", manager.isEnabled(undefinedDcFeature, true));
    }
}
