package com.atlassian.webdriver.bitbucket.page;

import com.atlassian.bitbucket.util.UrlUtils;
import com.atlassian.pageobjects.binder.WaitUntil;
import com.atlassian.pageobjects.elements.ElementBy;
import com.atlassian.pageobjects.elements.timeout.TimeoutType;
import com.atlassian.webdriver.bitbucket.element.Comment;
import com.atlassian.webdriver.bitbucket.element.DiffCommentForm;
import com.atlassian.webdriver.bitbucket.element.FileTree;
import com.atlassian.webdriver.bitbucket.element.UnifiedDiffFileContent;
import org.openqa.selenium.By;

import static com.atlassian.pageobjects.elements.query.Poller.waitUntilTrue;

public abstract class PullRequestDiffPage extends PullRequestPage<PullRequestDiffPage> {

    @ElementBy(cssSelector = ".file-content", pageElementClass = UnifiedDiffFileContent.class)
    protected UnifiedDiffFileContent fileContent;

    @ElementBy(className = FileTree.FILE_TREE_CONTAINER_CSS_CLASS, pageElementClass = FileTree.class)
    private FileTree tree;

    protected String queryParams = "";

    private final String path;
    private final String projectKey;
    private final long pullRequestId;
    private final String slug;

    public PullRequestDiffPage(String projectKey, String slug, long pullRequestId) {
        this(projectKey, slug, pullRequestId, null);
    }

    public PullRequestDiffPage(String projectKey, String slug, long pullRequestId, String path) {
        super(projectKey, slug, pullRequestId);
        this.projectKey = projectKey;
        this.slug = slug;
        this.pullRequestId = pullRequestId;
        this.path = path;
    }

    public PullRequestDiffPage(String projectKey, String slug, long pullRequestId, long commentId, String action) {
        this(projectKey, slug, pullRequestId);
        this.queryParams = "?" + UrlUtils.buildQueryParams("commentId", commentId, "action", action);
    }

    public void addComment(UnifiedDiffFileContent.Line line, String comment) {
        DiffCommentForm element = openNewComment(line, comment);
        element.submit();
    }

    public <T extends Comment> T addComment(Class<T> clazz, UnifiedDiffFileContent.Line line, String comment) {
        DiffCommentForm element = openNewComment(line, comment);
        Comment commentElement = element.submit();
        return pageBinder.bind(clazz, By.cssSelector(".comment[data-id=\"" + commentElement.getId() + "\"]"));
    }

    public void clickFileAndWaitUntilLoaded(String path) {
        waitUntilDiffTreeLoaded();
        tree.find(By.cssSelector("[href=\"#" + path + "\"]")).click();
        waitUntilFileContentLoaded();
    }

    public Comment getCommentAt(int index) {
        return getFileContent().getComments().get(index);
    }

    public UnifiedDiffFileContent getFileContent() {
        return fileContent;
    }

    public FileTree getFileTree() {
        return tree;
    }

    @Override
    public String getUrl() {
        String url = super.getUrl() + getDiffUrl() + queryParams;
        if (getPath() != null) {
            url += "#" + getPath();
        }
        return url;
    }

    public DiffCommentForm openNewComment(UnifiedDiffFileContent.Line line, String comment) {
        line.getAddComment().click();
        DiffCommentForm element = tree.find(By.className("new-comment-form"), DiffCommentForm.class, TimeoutType.COMPONENT_LOAD);
        element.setText(comment);
        return element;
    }

    @WaitUntil
    public void waitUntilPageLoaded() {
        waitUntilDiffTreeLoaded();
        waitUntilFileContentLoaded();
    }

    protected abstract String getDiffUrl();

    protected String getPath() {
        return path;
    }

    private void waitUntilDiffTreeLoaded() {
        waitUntilTrue(elementFinder.find(By.cssSelector(".file-tree ul"), TimeoutType.PAGE_LOAD).timed().isPresent());
    }

    private void waitUntilFileContentLoaded() {
        //don't require the content to be visible
        //files may have no content to show
        waitUntilTrue(elementFinder.find(By.cssSelector(
                "#commit-file-content .fully-loaded," +
                        "#commit-file-content .message-content," +
                        "#commit-file-content .binary-container"),
                TimeoutType.PAGE_LOAD).timed().isPresent());
    }
}
