package com.intland.codebeamer.functionaltest.page.trackers.documentview;

import com.codeborne.selenide.Condition;
import com.codeborne.selenide.ElementsCollection;
import com.codeborne.selenide.SelenideElement;
import com.codeborne.selenide.WebDriverRunner;
import com.intland.codebeamer.functionaltest.helper.Helper;
import com.intland.codebeamer.functionaltest.page.trackers.TrackerItemDetailsPage;
import com.intland.codebeamer.functionaltest.page.trackers.AddCommentDialog;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;

import java.util.List;

import static com.codeborne.selenide.Condition.*;
import static com.codeborne.selenide.Selenide.*;
import static org.testng.Assert.assertTrue;

/**
 * Copyright by Intland Software
 * <p>
 * All rights reserved.
 * <p>
 * This software is the confidential and proprietary information
 * of Intland Software. ("Confidential Information"). You
 * shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement
 * you entered into with Intland.
 */
public class RightPane {

    SelenideElement rightPane() {
        return $("#east");
    }

    public enum StatusType {
        ALL("All"),
        OPEN("Open"),
        RESOLVED_CLOSED("Resolved/Closed"),
        CLOSED("Closed"),
        RESOLVED("Resolved");

        private final String text;

        StatusType(String s) {
            text = s;
        }

        public boolean equalsName(String otherSelector) {
            return otherSelector != null && text.equals(otherSelector);
        }

        public String toString() {
            return this.text;
        }
    }

    public enum ActionType {
        LINK("Link"),
        DEPENDS("Depends"),
        RELATED("Resolved/Closed");

        private final String text;

        ActionType(String s) {
            text = s;
        }

        public boolean equalsName(String otherSelector) {
            return (otherSelector == null) ? false : text.equals(otherSelector);
        }

        public String toString() {
            return this.text;
        }
    }

    public enum Priority {
        NO("--"),
        LOWEST("Lowest"),
        LOW("Low"),
        NORMAL("Normal"),
        HIGH("High"),
        HIGHEST("Highest");

        private final String text;

        Priority(String s) {
            text = s;
        }

        public boolean equalsName(String otherSelector) {
            return (otherSelector == null) ? false : text.equals(otherSelector);
        }

        public String toString() {
            return this.text;
        }
    }

    public enum BusinessValue {
        NO("--"),
        NICE_TO_HAVE("Nice to have"),
        SHOULD_HAVE("Should have"),
        MUST_HAVE("Must have");

        private final String text;

        BusinessValue(String s) {
            text = s;
        }

        public boolean equalsName(String otherSelector) {
            return (otherSelector == null) ? false : text.equals(otherSelector);
        }

        public String toString() {
            return this.text;
        }
    }

    public PropertiesTab propertiesTab = new PropertiesTab();
    public ReleasesTab releasesTab = new ReleasesTab();
    public TestCaseLibraryTab testCaseLibraryTab = new TestCaseLibraryTab();
    public RequirementsLibraryTab requirementsLibraryTab = new RequirementsLibraryTab();

    public SelenideElement checkIfRightPaneIsCollapsed() {
        return rightPane().shouldBe(hidden.because("Right pane should be collapsed"));
    }

    public SelenideElement checkIfRightPaneIsNotCollapsed() {
        return rightPane().shouldNotBe(hidden.because("Right pane should not be collapsed"));
    }

    public ReleasesTab clickOnReleasesTab() {
        checkIfRightPaneIsNotCollapsed();
        $(By.xpath(".//li[@data-tab='release-pane']")).click();
        return releasesTab;
    }

    public PropertiesTab clickOnPropertiesTab() {
        checkIfRightPaneIsNotCollapsed();
        $(By.xpath(".//li[@data-tab='properties-tab']")).click();
        return propertiesTab;
    }

    public TestCaseLibraryTab clickOnTestCaseLibraryTab() {
        checkIfRightPaneIsNotCollapsed();
        $(By.xpath(".//li[@data-tab='test-plan-pane']")).click();
        return testCaseLibraryTab;
    }

    public RequirementsLibraryTab clickOnRequirementsLibraryTab() {
        checkIfRightPaneIsNotCollapsed();
        $(By.xpath(".//li[@data-tab='library-tab']")).click();
        requirementsLibraryTab.selectStatus(StatusType.ALL); //just to make sure because status is a user setting and accepted globally on every project
        return requirementsLibraryTab;
    }

    public void waitForRightTreeToLoad() {
        $("#j3_loading").should(disappear);
    }

    public ElementsCollection getAllVisibleTabs() {
        return $$(By.xpath(".//ul[@id='main-quick-icons']//li"));
    }

    interface RightPaneTab {

    }

    public class PropertiesTab implements RightPaneTab {

        SelenideElement detailsPanel() {
            return $(".issue-details.accordion-content.opened");
        }

        SelenideElement commentsPanel() {
            return $(".issue-comments.accordion-content.opened");
        }

        public ElementsCollection getAllAssociationsOf(String itemLabel, int index) {
            DocumentViewPage documentViewPage = page(DocumentViewPage.class);
            documentViewPage.leftPane.clickOnLeftTreeItem(itemLabel, index);
            clickOnPropertiesTab();
            clickOnRelationsPanel(true);
            return rightPane().findAll(By.xpath(".//table[@title='Associations']//tr[@class='relation-item']"));
        }

        public ElementsCollection getAllIncomingReferencesOf(String itemLabel, int index) {
            DocumentViewPage documentViewPage = page(DocumentViewPage.class);
            documentViewPage.leftPane.clickOnLeftTreeItem(itemLabel, index);
            clickOnPropertiesTab();
            clickOnRelationsPanel(true);
            return rightPane().findAll(By.xpath(".//table[@title='Incoming references']//tr[@class='relation-item']"));
        }

        public ElementsCollection getAllOutgoingReferencesOf(String itemLabel, int index) {
            DocumentViewPage documentViewPage = page(DocumentViewPage.class);
            documentViewPage.leftPane.clickOnLeftTreeItem(itemLabel, index);
            clickOnPropertiesTab();
            clickOnRelationsPanel(true);
            return rightPane().find(By.xpath(".//table[@title='Outgoing references']")).findAll("tr.relation-item");
        }

        public boolean isDetailsPanelOpened() {
            waitUntilRightPaneHasLoaded();
            return rightPane().find(".issue-details.accordion-content").isDisplayed();
            //rightPane().find(By.xpath("//h3[@class='issue-details-title accordion-header opened']")).exists();
        }

        public boolean isRelationsPanelOpened() {
            waitUntilRightPaneHasLoaded();
            return rightPane().find(By.xpath("//h3[@class='issue-associations-title accordion-header opened']")).exists();
        }

        public boolean isCommentsPanelOpened() {
            waitUntilRightPaneHasLoaded();
            return rightPane().find(By.xpath("//h3[@class='issue-comments-title accordion-header opened']")).exists();
        }

        public void clickOnDetailsPanel(boolean open) {
            if (open ^ isDetailsPanelOpened()) {
                actions().moveToElement(rightPane().find(By.xpath("//h3[contains(@class, 'issue-details-title accordion-header')]"))).click().perform();
            }
        }

        public void clickOnRelationsPanel(boolean open) {
            if (open ^ isRelationsPanelOpened()) {
                rightPane().find(By.xpath("//h3[contains(@class, 'issue-associations-title accordion-header')]")).click();
            }
        }

        public void clickOnCommentsPanel(boolean open) {
            if (open ^ isCommentsPanelOpened()) {
                rightPane().find(By.xpath("//h3[contains(@class, 'issue-comments-title accordion-header')]")).click();
            }
        }

        public AddCommentDialog clickOnAddComment() {
            assertTrue(isCommentsPanelOpened(), "comment panel should be opened");
            rightPane().find("a.addAttachmentIcon").click();
            return page(AddCommentDialog.class);
        }

        public TrackerItemDetailsPage clickOnItemLink(String itemLabel) {
            assertTrue(isDetailsPanelOpened(), "details panel should be opened");
            detailsPanel().find(By.linkText(itemLabel)).should(exist).click();
            return page(TrackerItemDetailsPage.class);
        }

        public ElementsCollection getAllCommentGroup() {
            return commentsPanel().findAll("#comments .commentGroup");
        }

        void waitUntilRightPaneHasLoaded() {
            List<WebElement> loaders = WebDriverRunner.getWebDriver().findElements(By.className("showBusySignDialog"));
            Wait().until(ExpectedConditions.invisibilityOfAllElements(loaders));
            sleep(1000);
        }

        public ElementsCollection getAllReleases() {
            return rightPane().findAll(By.xpath(".//td[@title='Release' and contains(@class, 'fieldValue')]//li[@class='token-input-token-facebook']/p"));
        }

        public String getStatus() {
            return rightPane().find(By.xpath(".//td[@title='Status' and contains(@class, 'fieldValue')]/span")).getText();
        }

        public void selectPriority(Priority priority) {
            rightPane().find("#dynamicChoice_references_2").selectOption(priority.text);
        }

        public void selectBusinessValue(BusinessValue bv) {
            rightPane().find(By.xpath(".//td[@title='Business Value']/following-sibling::td/select")).selectOption(bv.text);
        }

        public void clickOnSave() {
            rightPane().find(By.xpath("(.//input[@value='Save'])[2]")).click();
        }

        public void checkIfSaveIs(Condition condition) {
            clickOnDetailsPanel(true);
            rightPane().find(By.xpath(".//div[@class='saveControls']//input[@value='Save']")).shouldBe(condition);
        }

        public void checkIfAddAssociationIs(Condition condition) {
            clickOnRelationsPanel(true);
            rightPane().find(".addAssociationControl").shouldBe(condition);
        }

        public void checkIfAddCommentIs(Condition condition) {
            clickOnCommentsPanel(true);
            rightPane().find(".addCommentControl").shouldBe(condition);
        }

        public void checkIfPropertiesPanelIs(boolean enabled) {
            Condition condition = enabled ? visible : hidden;
            checkIfSaveIs(condition);
            checkIfAddAssociationIs(condition);
            checkIfAddCommentIs(condition);
        }

    }

    public class ReleasesTab implements RightPaneTab {

        SelenideElement releasesPane() {
            return $("#release-pane");
        }

        SelenideElement treeFilterBox() {
            return releasesPane().$(".treeFilterBox");
        }

        SelenideElement releasesTreePane() {
            return $("#releaseTreePane");
        }

        public boolean isReleaseNodeOpen() {
            return releasesPane().find(By.xpath(".//li[@role='treeitem' and contains(@class, 'jstree-open')]")).exists();
        }

        public void clickOnReleasesNode(boolean open) {
            if (open ^ isReleaseNodeOpen()) {
                releasesPane().find(By.xpath(".//li[@role='treeitem']/i")).click();
            }
        }

        public void fillFilter(String filterText) {
            if (filterText.isEmpty()) {
                treeFilterBox().clear();
                treeFilterBox().sendKeys(Keys.RETURN);
            } else {
                treeFilterBox().sendKeys(filterText, Keys.RETURN);
            }
            sleep(1000);
        }

        public ElementsCollection getAllTreeItems() {

            return releasesPane().findAll(By.xpath(".//ul[@class='jstree-children']//li[not(contains(@class, 'jstree-hidden'))]"));
        }

        public void openAllReleasesTreeItem() {
            waitForRightTreeToLoad();
            Helper.openAllRootNodes(releasesTreePane());
        }
    }

    public class TestCaseLibraryTab implements RightPaneTab {

        public SelenideElement testCaseLibraryPane() {
            return $("#test-plan-pane");
        }

        public SelenideElement testTreePane() {
            return $("#testTreePane");
        }

        public ElementsCollection getAllTreeItems() {
            Helper.openAllRootNodes(testTreePane());
            return testTreePane().findAll(By.xpath(".//li[@role='treeitem' and not(contains(@class, 'jstree-hidden'))]/a"));
        }

        public void fillFilter(String text) {
            testCaseLibraryPane().find(".treeFilterBox").sendKeys(text);
            sleep(1000);//wait for result
        }

        public void selectStatus(StatusType statusType) {
            $("#testStatusMeaning").selectOption(statusType.text);
        }

        public LinkTestCasesPage moveLibraryItemToLeftTreeItem(String libraryItemName, int libraryItemIndex, String leftTreeItemName, int leftTreeItemIndex) {
            Helper.openAllRootNodes(testTreePane());
            SelenideElement libraryItem = testTreePane().find(By.xpath("(.//li[@role='treeitem' and not(contains(@class, 'jstree-hidden'))]/a[text()='" + libraryItemName + "'])[" + libraryItemIndex + "]"));
            SelenideElement leftTreeItem = page(DocumentViewPage.class).leftPane.leftTreeItem(leftTreeItemName, leftTreeItemIndex);
            actions().clickAndHold(libraryItem).moveToElement(leftTreeItem).release().build().perform();
            return page(LinkTestCasesPage.class);
        }
    }

    public class RequirementsLibraryTab implements RightPaneTab {

        public SelenideElement requirementsLibraryPane() {
            return $("#library-tab");
        }

        public SelenideElement requirementsLibraryTreePane() {
            return $("#libraryPane");
        }

        public void fillFilter(CharSequence text) {
            requirementsLibraryPane().find(".treeFilterBox").sendKeys(text);
            sleep(1000);//wait for result
        }

        public ElementsCollection getAllTreeItems() {
            openAllRequirementsLibraryTreeItems();
            return requirementsLibraryTreePane().findAll(By.xpath(".//li[@role='treeitem' and not(contains(@class, 'jstree-hidden'))]/a"));
        }

        public void selectStatus(StatusType statusType) {
            $("#requirementStatusMeaning").selectOption(statusType.text);
        }

        public LinkTestCasesPage moveRequirementsLibraryItemToCenterPaneItem(String libraryItemName, int libraryItemIndex, String centerPaneItemName, int centerPaneItemIndex, boolean doRelease, ActionType actionType) {
            openAllRequirementsLibraryTreeItems();
            SelenideElement libraryItem = requirementsLibraryTreePane().find(By.xpath("(.//li[@role='treeitem' and not(contains(@class, 'jstree-hidden'))]/a[text()='" + libraryItemName + "'])[" + libraryItemIndex + "]"));
            SelenideElement centerPaneItem = page(DocumentViewPage.class).centerPane.centerPaneItem(centerPaneItemName, centerPaneItemIndex);
            if (doRelease) {
                //TODO haven't checked link
                actions().clickAndHold(libraryItem).moveToElement(centerPaneItem.find(By.xpath(".//span[@class='target-box' and contains(., '" + actionType.text + "')]"))).release().perform();
                if (actionType.equalsName(ActionType.LINK.text)) return page(LinkTestCasesPage.class);
                else return null;
            } else {
                actions().clickAndHold(libraryItem).moveToElement(centerPaneItem).perform();
                return null;
            }
        }

        public void moveRequirementsLibraryItemToLeftTreeItem(String libraryItemName, int libraryItemIndex, String leftTreeItemName, int leftTreeItemIndex) {
            openAllRequirementsLibraryTreeItems();
            SelenideElement libraryItem = requirementsLibraryTreePane().find(By.xpath("(.//li[@role='treeitem' and not(contains(@class, 'jstree-hidden'))]/a[text()='" + libraryItemName + "'])[" + libraryItemIndex + "]"));
            SelenideElement leftTreeItem = page(DocumentViewPage.class).leftPane.leftTreeItem(leftTreeItemName, leftTreeItemIndex);
            actions().clickAndHold(libraryItem).moveToElement(leftTreeItem).release().build().perform();
            sleep(5000); //because of bug in the left tree which causes multiple items get rendered in the tree
        }

        public void openAllRequirementsLibraryTreeItems() {
            waitForRightTreeToLoad();
            Helper.openAllRootNodes(requirementsLibraryTreePane());
        }
    }

}
