package it.com.atlassian.stash;

import com.atlassian.bitbucket.test.NavigationTestHelper;
import com.atlassian.webdriver.bitbucket.element.RevisionHistoryDialog;
import com.atlassian.webdriver.bitbucket.element.SideBySideDiffFileContent;
import com.atlassian.webdriver.bitbucket.page.FileLayoutPage;
import com.atlassian.webdriver.bitbucket.page.FileSideBySideDiffPage;
import com.atlassian.webdriver.bitbucket.page.FileUnifiedDiffPage;
import com.google.common.collect.Lists;
import it.com.atlassian.stash.rules.WebStorageCleanUpRule;
import org.junit.Test;
import org.junit.rules.TestRule;

import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Optional;

import static com.atlassian.bitbucket.test.TestRuleOrderingSyntax.outerRules;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;

public class ViewSideBySideDiffTest extends BaseFileContentTest {

    public static final String FILE1_AUTHOR = "Federico Silva Armas";
    public static final String FILE1_DATE = "2012-02-22T00:07:17-0600";
    public static final String FILE1_DIR = "ChangeSet";
    public static final String FILE1_NAME = "file1.txt";
    public static final String FILE1_REVISION = "b4d378388c2dc3840ff5dcf64b4ac0f1ffc17cb9";
    public static final String FILE1_REVISION_SORT = "b4d378388c2";

    @Override
    protected List<TestRule> getRetryRuleChain() {
        return outerRules(new WebStorageCleanUpRule()).around(super.getRetryRuleChain());
    }

    @Test
    public void testLoadUntilRevision() throws Exception {
        checkLoadUntilRevisionInTz(Optional.empty());
    }

    @Test
    public void testLoadUntilRevisionInServerTz() {
        TimeZoneTestHelper.withServerTimeZone(Optional.of(ZoneOffset.MIN), this::checkLoadUntilRevisionInTz);
        TimeZoneTestHelper.withServerTimeZone(Optional.of(ZoneOffset.MAX), this::checkLoadUntilRevisionInTz);
    }

    @Test
    public void testLoadUntilRevisionInUserTz() {
        TimeZoneTestHelper.withUserTimeZone(Optional.of(ZoneOffset.MIN), this::checkLoadUntilRevisionInTz);
        TimeZoneTestHelper.withUserTimeZone(Optional.of(ZoneOffset.MAX), this::checkLoadUntilRevisionInTz);
    }

    @Test
    public void testSwitchUntilRevision() throws Exception {
        FileLayoutPage.RevisionSpecifier revisionSpecifier = new FileLayoutPage.RevisionSpecifier(null, FILE1_REVISION);
        FileSideBySideDiffPage page = loginAsAdmin(FileUnifiedDiffPage.class, getProjectKey(), getRepoSlug(), getUrlPathComponent(FILE1_DIR, FILE1_NAME), revisionSpecifier).switchToSideBySide();

        assertEquals("master", page.getBranchSelector().getSelectedItemName());

        assertBreadcrumbs(page.getBreadcrumbs(), getRepoSlug(), FILE1_DIR, FILE1_NAME);

        assertEquals(FILE1_AUTHOR, page.getCurrentRevisionAuthor());
        assertEquals(FILE1_REVISION_SORT, page.getCurrentRevisionId());
        assertEquals(FILE1_REVISION, getUntilRevisionFromUrl());

        assertCorrectDate(page, FILE1_DATE);

        assertFile1AtB4D37838(page.getFileContent());

        RevisionHistoryDialog revisionHistoryDialog = page.getRevisionHistoryDialog();

        revisionHistoryDialog.open();
        page = page.loadUntilRevision("c4a3c85d62068dcfa1cca63c3367235facc0e301");
        page.getFileContent().waitUntilPageLoaded();

        assertEquals("master", page.getBranchSelector().getSelectedItemName());

        assertBreadcrumbs(page.getBreadcrumbs(), getRepoSlug(), FILE1_DIR, FILE1_NAME);

        assertEquals("Federico Silva Armas", page.getCurrentRevisionAuthor());
        assertEquals("c4a3c85d620", page.getCurrentRevisionId());
        assertEquals("c4a3c85d62068dcfa1cca63c3367235facc0e301", getUntilRevisionFromUrl());

        assertCorrectDate(page, "2012-02-22T01:06:08-0500");

        assertFile1AtC4A3C85D(page.getFileContent());
    }

    @Test
    public void navigateSegments() {
        String revision = "67ea12f085107dcecdf15bb00c6f60c66b92d620";
        FileLayoutPage.RevisionSpecifier revisionSpecifier = new FileLayoutPage.RevisionSpecifier(null, revision);
        final FileSideBySideDiffPage page = loginAsAdmin(FileUnifiedDiffPage.class, getProjectKey(), getRepoSlug(),
                getUrlPathComponent(FILE1_DIR, "bootstrap", "js", "bootstrap-modal.js"), revisionSpecifier).switchToSideBySide();

        SideBySideDiffFileContent fileContent = page.getFileContent();
        List<SideBySideDiffFileContent.Lineset> changeLinesets = Lists.newArrayList(
                fileContent.getLines(32,  37,  -1,  -1),
                fileContent.getLines(71,  75,  65,  65),
                fileContent.getLines(186, 186, 176, 201),
                fileContent.getLines(-1,   -1, 262, 263)
        );

        page.scrollToTop();
        NavigationTestHelper.testNavigation(changeLinesets, options -> {
            page.moveToNextChange(options.isExpectingMovement());
            return null;
        }, options -> {
            page.moveToPreviousChange(options.isExpectingMovement());
            return null;
        }, lineset -> {
            lineset.assertHasFocus();
            return null;
        });
    }

    @Test
    public void scrollToFirstChange() {
        String revision = "67ea12f085107dcecdf15bb00c6f60c66b92d620";
        FileLayoutPage.RevisionSpecifier revisionSpecifier = new FileLayoutPage.RevisionSpecifier(null, revision);
        FileUnifiedDiffPage diffPage = loginAsAdmin(FileUnifiedDiffPage.class, getProjectKey(), getRepoSlug(),
                getUrlPathComponent(FILE1_DIR, "bootstrap", "js", "bootstrap-modal.js"), revisionSpecifier);
        Integer fileContentTop = diffPage.getFileContent().getToolbar().getLocation().getY();

        FileSideBySideDiffPage page = diffPage.switchToSideBySide();
        Integer pageScroll = page.getScrollInfo().getScrollTop();

        assertThat("Page (scrollTop:" + pageScroll + "px) is scrolled into the diff view (past " + fileContentTop + "px).", pageScroll, greaterThan(fileContentTop));
    }

    private void assertFile1AtB4D37838(SideBySideDiffFileContent fileContent) {
        List<SideBySideDiffFileContent.Line> fromSource = fileContent.getFromLines();
        List<SideBySideDiffFileContent.Line> toSource = fileContent.getToLines();

        assertThat(fromSource, hasSize(5));
        assertLineContent("Initial content - updated", fromSource.get(0));
        assertLineContent("", fromSource.get(1));
        assertLineContent("more updates ", fromSource.get(2));
        assertLineContent("", fromSource.get(3));
        assertLineIsDelete("age", fromSource.get(4));

        assertThat(toSource, hasSize(5));
        assertLineContent("Initial content - updated", toSource.get(0));
        assertLineContent("", toSource.get(1));
        assertLineContent("more updates ", toSource.get(2));
        assertLineContent("", toSource.get(3));
        assertLineIsAdd("agefwrw", toSource.get(4));
    }

    private void assertFile1AtC4A3C85D(SideBySideDiffFileContent fileContent) {
        List<SideBySideDiffFileContent.Line> fromSource = fileContent.getFromLines();
        List<SideBySideDiffFileContent.Line> toSource = fileContent.getToLines();

        assertThat(fromSource, hasSize(3));
        assertLineContent("Initial content - updated", fromSource.get(0));
        assertLineContent("", fromSource.get(1));
        assertLineIsDelete("more updates", fromSource.get(2));

        assertThat(toSource, hasSize(5));
        assertLineContent("Initial content - updated", toSource.get(0));
        assertLineContent("", toSource.get(1));
        assertLineIsAdd("more updates ", toSource.get(2));
        assertLineIsAdd("", toSource.get(3));
        assertLineIsAdd("age", toSource.get(4));
    }

    private Void checkLoadUntilRevisionInTz(Optional<? extends ZoneId> zoneId) {
        FileLayoutPage.RevisionSpecifier revisionSpecifier = new FileLayoutPage.RevisionSpecifier(null, FILE1_REVISION);
        FileSideBySideDiffPage page = loginAsAdmin(FileUnifiedDiffPage.class, getProjectKey(), getRepoSlug(), getUrlPathComponent(FILE1_DIR, FILE1_NAME), revisionSpecifier).switchToSideBySide();

        assertEquals("master", page.getBranchSelector().getSelectedItemName());

        assertBreadcrumbs(page.getBreadcrumbs(), getRepoSlug(), FILE1_DIR, FILE1_NAME);

        assertEquals("Federico Silva Armas", page.getCurrentRevisionAuthor());
        assertEquals("b4d378388c2", page.getCurrentRevisionId());

        assertCorrectDate(page, FILE1_DATE, zoneId);

        assertFile1AtB4D37838(page.getFileContent());

        return null;
    }
}
