package com.atlassian.webdriver.bitbucket.page;

import com.atlassian.pageobjects.elements.ElementBy;
import com.atlassian.pageobjects.elements.PageElement;
import com.atlassian.pageobjects.elements.query.Poller;
import com.atlassian.webdriver.bitbucket.element.CodeMirrorSourceFileContent;
import com.atlassian.webdriver.bitbucket.element.LegacySourceFileContent;
import com.atlassian.webdriver.bitbucket.element.SourceFileContent;
import com.atlassian.webdriver.bitbucket.util.ElementUtils;
import com.google.common.collect.Lists;
import org.openqa.selenium.By;

import java.util.Collection;
import java.util.List;

import static com.atlassian.webdriver.bitbucket.util.ElementUtils.scrollIntoViewIfNeeded;

public class FileSourcePage extends FileContentPage<SourceFileContent> {

    @ElementBy(className = "file-blame")
    private PageElement blameButton;

    @ElementBy(className = "source-view", pageElementClass = CodeMirrorSourceFileContent.class)
    private CodeMirrorSourceFileContent codemirrorFileContent;

    private Boolean isLegacy;

    @ElementBy(className = "source-view", pageElementClass = LegacySourceFileContent.class)
    private LegacySourceFileContent legacyFileContent;

    @ElementBy(className = "raw-view-link")
    private PageElement rawLink;

    public FileSourcePage(String projectKey, String repoSlug, String path) {
        super(projectKey, repoSlug, path);
    }

    public FileSourcePage(String projectKey, String repoSlug, String path, String commitId) {
        super(projectKey, repoSlug, path, new RevisionSpecifier(commitId, null));
    }

    public FileSourcePage(String projectKey, String repoSlug, String path, RevisionSpecifier revisionSpecifier) {
        super(projectKey, repoSlug, path, revisionSpecifier);
    }

    @Override
    public SourceFileContent getFileContent() {
        return codemirrorFileContent;
    }

    @Override
    protected String getPathComponent() {
        return "browse";
    }

    public String getRawLink() {
        getFileContent().waitUntilFileContentLoaded();
        return rawLink.getAttribute("href");
    }

    public Collection<String> getWarningMessages() {
        return ElementUtils.getElementTexts(getFileContent().findAll(By.className("aui-message-warning")));
    }

    @Override
    public FileSourcePage loadUntilRevision(String revisionId) {
        return loadRevision(revisionId, FileSourcePage.class);
    }

    public List<BlameRow> showBlame() {
        getFileContent().waitUntilFileContentLoaded();
        waitUntilEventFired("bitbucket.internal.feature.fileContent.fileBlameExpandedStateChanged",
                () -> blameButton.click());
        return getBlame(By.cssSelector(".blame[data-span]"), CodeMirrorBlameRow.class);
    }

    private <T extends BlameRow> List<BlameRow> getBlame(By locator, Class<T> clazz) {
        Poller.waitUntilTrue(elementFinder.find(locator).timed().isPresent());
        return Lists.transform(elementFinder.findAll(locator), element -> pageBinder.bind(clazz, element));
    }

    public static class CodeMirrorBlameRow implements BlameRow {

        private final PageElement firstLine;

        public CodeMirrorBlameRow(PageElement firstLine) {
            this.firstLine = firstLine;
        }

        @Override
        public String getAuthor() {
            // HACK - we should be using the .getText(), but WebDriver is messed up and that won't work for offscreen elements
            // So we use the title, understanding this is brittle.
            return firstLine.find(By.className("blame-author")).getAttribute("title");
        }

        @Override
        public String getCommit() {
            return scrollIntoViewIfNeeded(firstLine).find(By.className("commitid")).getText();
        }

        @Override
        public String getDate() {
            return scrollIntoViewIfNeeded(firstLine).find(By.className("blame-timestamp")).getText();
        }

        @Override
        public int getSpan() {
            return Integer.parseInt(firstLine.getAttribute("data-span"));
        }
    }

    public interface BlameRow {

        String getAuthor();

        String getCommit();

        String getDate();

        int getSpan();
    }
}