package com.atlassian.webdriver.bitbucket.element.tasks;

import com.atlassian.pageobjects.binder.WaitUntil;
import com.atlassian.pageobjects.elements.PageElement;
import com.atlassian.pageobjects.elements.WebDriverLocatable;
import com.atlassian.pageobjects.elements.query.Poller;
import com.atlassian.pageobjects.elements.timeout.TimeoutType;
import com.atlassian.webdriver.bitbucket.element.LegacyElementPageObject;
import org.hamcrest.Matchers;
import org.openqa.selenium.By;

import javax.annotation.Nonnull;
import java.util.List;

public class TaskTable extends LegacyElementPageObject {

    public static final String SELECTOR = "#task-list-dialog .task-list";

    public TaskTable(@Nonnull PageElement element) {
        super(element);
    }

    public TaskTable() {
        super(By.cssSelector(SELECTOR));
    }

    public TaskTable(By locator, WebDriverLocatable parent) {
        super(locator, parent);
    }

    @WaitUntil
    private void isLoaded() {
        Poller.waitUntilFalse(find(By.className("spinner")).timed().isPresent());
        // ensure there's at least one row in the table
        Poller.waitUntilTrue(find(By.className(Row.CLASS)).timed().isVisible());
    }

    public Row getRowByCommentId(long commentId) {
        for (Row row : getRows()) {
            if (row.getCommentId() == commentId) {
                return row;
            }
        }
        return null;
    }

    public int size() {
        return getRows().size();
    }

    private List<Row> getRows() {
        return findAll(By.className(Row.CLASS), Row.class);
    }

    public Row getRowAt(int position) {
        List<Row> rows = getRows();
        return (rows.size() > position ? rows.get(position) : null);
    }

    public static class Row extends LegacyElementPageObject {

        public static final String CLASS = "task-container";

        public Row(@Nonnull PageElement container) {
            super(container);
        }

        public Row(WebDriverLocatable locatable, TimeoutType timeoutType) {
            super(locatable, timeoutType);
        }

        public long getCommentId() {
            return Long.parseLong(getTask().getAttribute("data-comment-id"));
        }

        public TaskState getState() {
            return getTask().getState();
        }

        public String getText() {
            return find(By.className("message")).getText();
        }

        public String getFileName() {
            // expands the row so that the filename becomes visible,
            // otherwise calling getText() on a present but invisible element will return a empty string
            if (!isExpanded()) {
                expand();
            }
            return getCommentDiffAnchor().getText();
        }

        public String getFilePath() {
            return getCommentDiffAnchor().find(By.className("aui-button")).getAttribute("data-path");
        }

        public PageElement getCheckbox() {
            return find(By.className("task-checkbox"));
        }

        public PageElement getRemoveButton() {
            PageElement button = find(By.className("task-list-dialog-remove-button"));
            button.javascript().execute("jQuery(arguments[0]).show()");
            return button;
        }

        public Row resolveTask() {
            if (!getState().equals(TaskState.OPEN)) {
                throw new IllegalStateException("Expected task to be in open state to resolve");
            }
            return clickAndExpectState(TaskState.RESOLVED);
        }

        public Row reopenTask() {
            if (!getState().equals(TaskState.RESOLVED)) {
                throw new IllegalStateException("Expected task to be in resolved state to reopen");
            }
            return clickAndExpectState(TaskState.OPEN);
        }

        public Row expand() {
            if (!isCollapsed()) {
                throw new IllegalStateException("Task row is already expanded or expanding");
            }
            find(By.className("task-content")).click();
            Poller.waitUntilTrue(timed().hasClass("expanded"));
            return this;
        }

        public Row collapse() {
            if (!isExpanded()) {
                throw new IllegalStateException("Task row is already collapsed or collapsing");
            }
            find(By.className("task-content")).click();
            Poller.waitUntilTrue(timed().hasClass("collapsed"));
            return this;
        }

        public void deleteTask() {
            expand().getTask().delete();
        }

        public Task editTask() throws Exception {
            return expand().getTask().edit();
        }

        protected Task getTask() {
            return find(By.className("task"), Task.class);
        }

        private Row clickAndExpectState(TaskState expectedState) {
            getCheckbox().click();
            Poller.waitUntil(getTask().timed().getAttribute("data-task-state"), Matchers.equalToIgnoringCase(expectedState.name()));
            return this;
        }

        private PageElement getCommentDiffAnchor() {
            return find(By.className("comment-diff-anchor"));
        }

        private boolean isCollapsed() {
            return hasClass("collapsed");
        }

        private boolean isExpanded() {
            return hasClass("expanded");
        }
    }
}
