package com.atlassian.bitbucket.installer.scripts;

import com.google.common.collect.ImmutableMap;
import com.install4j.api.context.WizardContext;
import org.junit.Before;
import org.junit.Test;

import java.io.File;
import java.util.Map;

import static com.atlassian.bitbucket.installer.InstallerConstants.*;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.*;

public class SummaryScreenTest extends BaseInstallerTest {

    private static final String NEXT_BUTTON_TEXT = "next.button.text";
    private static final String SERVICE_LABEL_INSTALL = "service.label.install";
    private static final String YES = "yes";
    private static final String NO = "no";
    private static final String SERVICE_LABEL_UPGRADE = "service.label.upgrade";
    private SummaryScreen summaryScreen = new SummaryScreen(getContext(), getUtils());

    private WizardContext wizardContext = createWizardContext(getContext());
    private File file = new File("/stash/home/dir");

    @Before
    public void setup() {
        setI18nMessageReturn(I18N_SUMMARY_INSTALL_NEXT_BUTTON_TEXT, NEXT_BUTTON_TEXT);
        setI18nMessageReturn(I18N_SUMMARY_SERVICE_LABEL_INSTALL, SERVICE_LABEL_INSTALL);
        setI18nMessageReturn(I18N_SUMMARY_SERVICE_LABEL_UPGRADE, SERVICE_LABEL_UPGRADE);
        setI18nMessageReturn(I18N_GENERIC_TEXT_YES, YES);
        setI18nMessageReturn(I18N_GENERIC_TEXT_NO, NO);

        when(getInstallationDetails().getHomeDirectory()).thenReturn(file);
        when(getContext().getVariable(KEY_STASH_USER_QUERY)).thenReturn(1);
    }

    @Test
    public void testShouldReturnTrueIfConsoleAndUnattended() throws Exception {
        isContextConsole(true, true);

        assertTrue(summaryScreen.validationScriptAtSummaryScreen());
    }

    @Test
    public void testShouldFinishInstallationIfExit() throws Exception {
        isContextConsole(true, false);
        givenConfirmDialogReturns(false);

        summaryScreen.validationScriptAtSummaryScreen();

        verify(getContext()).finish(0);
    }

    @Test
    public void testShouldReturnTrueIfGitNotFoundAndContinue() throws Exception {
        givenGitMethodsAndDialogReturn(false, false, true);

        assertTrue(summaryScreen.validationScriptAtSummaryScreen());
    }

    @Test
    public void testShouldReturnTrueIfGitFoundGitUnsupportedAndContinue() throws Exception {
        givenGitMethodsAndDialogReturn(true, false, true);

        assertTrue(summaryScreen.validationScriptAtSummaryScreen());
    }

    @Test
    public void testShouldReturnTrueIfGitIsOK() throws Exception {
        givenGitMethodsAndDialogReturn(true, true, true);

        assertTrue(summaryScreen.validationScriptAtSummaryScreen());
    }

    @Test
    public void testShouldReturnFalseIfGitNotFoundAndStop() throws Exception {
        givenGitMethodsAndDialogReturn(false, false, false);

        assertFalse(summaryScreen.validationScriptAtSummaryScreen());
    }

    @Test
    public void testShouldReturnFalseIfGitNotSupportedAndStop() throws Exception {
        givenGitMethodsAndDialogReturn(true, false, false);

        assertFalse(summaryScreen.validationScriptAtSummaryScreen());
    }

    @Test
    public void testShouldGoBackIfUserChooseNotOverrideTheService() throws Exception {
        givenInstallerFlagsForServiceOverride(true, true, true, false);

        summaryScreen.preSummaryScreen();

        verify(getContext()).goBack(1);
    }

    @Test
    public void testShouldNotGoBackIfRequirementsNotMetOrUserChoosesToOverride() throws Exception {
        assertNotGoBackIfRequirementsNotMetOrUserChoosesToOverride(false, true, true, false);
        assertNotGoBackIfRequirementsNotMetOrUserChoosesToOverride(true, false, true, false);
        assertNotGoBackIfRequirementsNotMetOrUserChoosesToOverride(true, true, false, false);
        assertNotGoBackIfRequirementsNotMetOrUserChoosesToOverride(false, false, false, false);
        assertNotGoBackIfRequirementsNotMetOrUserChoosesToOverride(true, false, false, false);
        assertNotGoBackIfRequirementsNotMetOrUserChoosesToOverride(true, false, false, true);
    }

    @Test
    public void testShouldSetVariablesForSummaryScreen() throws Exception {
        givenInstallerFlagsForServiceOverride(false, true, true, true);

        summaryScreen.preSummaryScreen();

        verify(wizardContext).setNextButtonText(NEXT_BUTTON_TEXT);
        verify(getInstallationDetails()).updateContext(getContext());
    }

    @Test
    public void testShouldShowAndSetInstallToLabelWhenIsNewInstallAndNotMacOS() throws Exception {
        givenInstallerFlagsForServiceOverride(true, true, false, false);
        setIsMacOC(false);
        summaryScreen.preSummaryScreen();

        verifyContextSetVariables(ImmutableMap.<String, Object>of(
                KEY_INSTALLER_SUMMARY_SERVICE_LABEL, SERVICE_LABEL_INSTALL,
                KEY_APP_SERVICE_LABEL_VISIBLE, true
        ));
    }

    @Test
    public void testShouldShowAndSetInstallToLabelWhenIsNewInstall() throws Exception {
        givenInstallerFlagsForServiceOverride(true, true, false, false);

        summaryScreen.preSummaryScreen();

        verifyContextSetVariables(ImmutableMap.<String, Object>of(
                KEY_INSTALLER_SUMMARY_SERVICE_LABEL, SERVICE_LABEL_INSTALL,
                KEY_APP_SERVICE_LABEL_VISIBLE, true
        ));
    }

    @Test
    public void testShouldNotShowAndSetInstallToLabelWheneverItsOnMacOS() throws Exception {
        givenInstallerFlagsForServiceOverride(true, true, false, false);
        setIsMacOC(true);

        summaryScreen.preSummaryScreen();

        verifyContextSetVariables(ImmutableMap.<String, Object>of(
                KEY_APP_SERVICE_LABEL_VISIBLE, false,
                KEY_APP_INSTALL_SERVICE, false
        ));
    }

    @Test
    public void testShouldShowAndSetUpgradeToLabelWhenIsUpgrade() throws Exception {
        givenInstallerFlagsForServiceOverride(false, true, true, false);
        setIsMacOC(false);
        setIsAdmin(true);

        summaryScreen.preSummaryScreen();

        verifyContextSetVariables(ImmutableMap.<String, Object>of(
                KEY_INSTALLER_SUMMARY_SERVICE_LABEL, SERVICE_LABEL_UPGRADE,
                KEY_APP_INSTALL_SERVICE, true,
                KEY_APP_SERVICE_LABEL_VISIBLE, true
        ));
    }

    @Test
    public void testShouldShowAndSetUpgradeToLabelWhenIsNewInstall() throws Exception {
        givenInstallerFlagsForServiceOverride(false, true, true, false);
        setIsMacOC(false);
        setIsAdmin(true);

        summaryScreen.preSummaryScreen();

        verifyContextSetVariables(ImmutableMap.<String, Object>of(
                KEY_INSTALLER_SUMMARY_SERVICE_LABEL, SERVICE_LABEL_UPGRADE,
                KEY_APP_INSTALL_SERVICE, true,
                KEY_APP_SERVICE_LABEL_VISIBLE, true
        ));
    }

    @Test
    public void testShouldHideServiceLabelWhenIsUpgrade() throws Exception {
        givenInstallerFlagsForServiceOverride(false, true, false, false);
        setIsMacOC(false);
        setIsAdmin(true);

        summaryScreen.preSummaryScreen();

        verifyContextSetVariables(ImmutableMap.<String, Object>of(
                KEY_APP_INSTALL_SERVICE, false,
                KEY_APP_SERVICE_LABEL_VISIBLE, false
        ));
    }

    @Test
    public void testShouldHideServiceLabelWhenIsUpgradeAndHasExistingServiceNoAdminRight() throws Exception {
        givenInstallerFlagsForServiceOverride(false, true, true, false);
        setIsMacOC(false);
        setIsAdmin(false);

        summaryScreen.preSummaryScreen();

        verifyContextSetVariables(ImmutableMap.<String, Object>of(
                KEY_APP_INSTALL_SERVICE, false,
                KEY_APP_SERVICE_LABEL_VISIBLE, false
        ));
    }

    @Test
    public void testShouldHideServiceLabelWhenIsUpgradeAndNoExistingServiceAndNoAdminRight() throws Exception {
        givenInstallerFlagsForServiceOverride(false, true, false, false);
        setIsMacOC(false);
        setIsAdmin(false);

        summaryScreen.preSummaryScreen();

        verifyContextSetVariables(ImmutableMap.<String, Object>of(
                KEY_APP_INSTALL_SERVICE, false,
                KEY_APP_SERVICE_LABEL_VISIBLE, false
        ));
    }

    @Test
    public void testShouldHideServiceLabelWhenIsNewInstall() throws Exception {
        givenInstallerFlagsForServiceOverride(false, true, false, false);

        summaryScreen.preSummaryScreen();

        verifyContextSetVariables(ImmutableMap.<String, Object>of(
                KEY_APP_INSTALL_SERVICE, false,
                KEY_APP_SERVICE_LABEL_VISIBLE, false
        ));
    }

    @Test
    public void testShouldSetValueAsYesWhenInstallService() throws Exception {
        givenInstallerFlagsForServiceOverride(false, true, true, false);

        summaryScreen.preSummaryScreen();

        verify(getContext()).setVariable(KEY_SUMMARY_SERVICE_TEXT, YES);
    }

    @Test
    public void testShouldSetValueAsNoWhenDoNotInstallService() throws Exception {
        givenInstallerFlagsForServiceOverride(true, false, true, false);

        summaryScreen.preSummaryScreen();

        verify(getContext()).setVariable(KEY_SUMMARY_SERVICE_TEXT, NO);
    }

    @Test
    public void testShouldSetDeleteStashUserValueAsYesWhenUserDeleteIsTrue() throws Exception {
        givenInstallerFlagsForServiceOverride(false, false, true, false);
        when(getContext().getVariable(KEY_STASH_USER_QUERY)).thenReturn(0);
        when(getContext().getBooleanVariable(KEY_DELETE_STASH_USER)).thenReturn(true);

        summaryScreen.preSummaryScreen();

        verify(getContext()).setVariable(KEY_SUMMARY_DELETE_STASH_USER_TEXT, YES);
    }

    @Test
    public void testShouldSetDeleteStashUserValueAsNoWhenUserDeleteIsFalse() throws Exception {
        givenInstallerFlagsForServiceOverride(false, false, true, false);
        when(getContext().getVariable(KEY_STASH_USER_QUERY)).thenReturn(0);
        when(getContext().getBooleanVariable(KEY_DELETE_STASH_USER)).thenReturn(false);

        summaryScreen.preSummaryScreen();

        verify(getContext()).setVariable(KEY_SUMMARY_DELETE_STASH_USER_TEXT, NO);
    }

    @Test
    public void testShouldSetDeleteStashUserValueAsNoWhenStashUserDoesntExist() throws Exception {
        givenInstallerFlagsForServiceOverride(false, false, true, false);
        when(getContext().getVariable(KEY_STASH_USER_QUERY)).thenReturn(1);

        summaryScreen.preSummaryScreen();

        verify(getContext(), never()).setVariable(eq(KEY_SUMMARY_DELETE_STASH_USER_TEXT), anyString());
    }

    private void verifyContextSetVariables(Map<String, Object> variableMap) {
        for (String key : variableMap.keySet()) {
            verify(getContext()).setVariable(key, variableMap.get(key));
        }
    }

    private void assertNotGoBackIfRequirementsNotMetOrUserChoosesToOverride(boolean isNewInstall, boolean isInstallService, boolean isServiceExists, boolean selectedOption) {
        givenInstallerFlagsForServiceOverride(isNewInstall, isInstallService, isServiceExists, selectedOption);

        summaryScreen.preSummaryScreen();

        verify(getContext(), never()).goBack(1);
    }

    private void givenInstallerFlagsForServiceOverride(boolean isNewInstall, boolean isInstallService, boolean isServiceExists, boolean selectedOption) {
        if (isNewInstall) {
            setDefaultInstall();
        } else {
            setUpgrade();
        }
        when(getInstallationDetails().isInstallService()).thenReturn(isInstallService);
        when(getContext().getBooleanVariable(KEY_APP_INSTALL_SERVICE)).thenReturn(isInstallService);
        when(getContext().getBooleanVariable(KEY_APP_SERVICE_EXISTS)).thenReturn(isServiceExists);
        givenConfirmDialogReturns(selectedOption);
    }

    private void givenConfirmDialogReturns(boolean returnValue) {
        when(getUtils().showConfirmDialog(any(String.class), any(String.class), any(String.class), any(Boolean.class)))
                .thenReturn(returnValue);
    }


    private void givenGitMethodsAndDialogReturn(Boolean isGitFound, Boolean isGitSupported, boolean dialogReturn) {
        when(getInstallationDetails().isGitFound()).thenReturn(isGitFound);
        when(getInstallationDetails().isGitSupported()).thenReturn(isGitSupported);
        givenConfirmDialogReturns(dialogReturn);
    }

    private void isContextConsole(Boolean isConsole, Boolean unattended) {
        when(getContext().isConsole()).thenReturn(isConsole);
        when(getContext().isUnattended()).thenReturn(unattended);
    }

    private void setIsMacOC(boolean isMacOC) {
        when(getUtils().isMacOS()).thenReturn(isMacOC);
    }

    private void setIsAdmin(boolean isAdmin) {
        when(getInstallationDetails().isAdmin()).thenReturn(isAdmin);
    }
}