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

import com.codeborne.selenide.CollectionCondition;
import com.codeborne.selenide.Condition;
import com.codeborne.selenide.ElementsCollection;
import com.codeborne.selenide.SelenideElement;
import com.codeborne.selenide.ex.UIAssertionError;
import com.intland.codebeamer.functionaltest.helper.Helper;
import com.intland.codebeamer.functionaltest.page.BasePage;
import com.intland.codebeamer.functionaltest.page.trackers.TrackerItemDetailsPage;
import com.intland.codebeamer.functionaltest.page.common.ConfirmationDialogPage;
import com.intland.codebeamer.functionaltest.page.common.EditorComponent;
import com.intland.codebeamer.functionaltest.page.common.IsPageLoaded;
import com.intland.codebeamer.functionaltest.page.trackers.*;
import com.intland.codebeamer.functionaltest.page.trackers.reviewdialog.PreviewSelectionStepPage;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;

import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.codeborne.selenide.Condition.*;
import static com.codeborne.selenide.Selenide.*;

/**
 * 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 CenterPane {

    public EditorComponent editorComponent = new EditorComponent();

    public SelenideElement centerPane() {
        return $("#centerDiv");
    }

    public SelenideElement moreMenuLink() {
        return $(By.xpath(".//a[text()='more']/following-sibling::img"));
    }

    public SelenideElement centerPaneItem(String itemLabel, int index) {
        return centerPane().find(By.xpath("(.//tr[.//span[3 and text()='" + itemLabel + "']])[" + index + "]"));
    }

    public enum CenterPaneContextMenuItem {
        OPEN("Open", TrackerItemDetailsPage.class),
        NEW_CHILD("New Child", null),
        INSERT_NEW_ITEM_AFTER_THIS("Insert a new Item after this", null),
        INSERT_NEW_ITEM_BEFORE_THIS("Insert a new Item before this", null),
        ADD_ASSOCIATION("Add Association", AddAssociationDialog.class),
        COPY("Copy", null),
        DELETE("Delete...", ConfirmationDialogPage.class),
        PASTE_AS_NEW_CHILD("Paste as New Child", AssociationTypeSelectionDialogPage.class),
        PASTE_ABOVE_THIS("Paste Above This", AssociationTypeSelectionDialogPage.class),
        PASTE_BELOW_THIS("Paste Below This", AssociationTypeSelectionDialogPage.class),
        ADD_COMMENT("Add Comment/Attachment", AddCommentDialog.class),
        ADD_COMMENT_VIA_OFFICE("Add Comment via Office", AssociationTypeSelectionDialogPage.class);

        private final String text;
        public final Class<?> pageObjectClass;

        CenterPaneContextMenuItem(String s, Class<?> pageObjectClass) {
            text = s;
            this.pageObjectClass = pageObjectClass;
        }

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

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

    public enum TransitionType {
        DEFINE("Define"),
        APPROVE("Approve"),
        REJECT("Reject"),
        ACCEPT("Accept");

        private final String text;

        TransitionType(String s) {
            text = s;
        }

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

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

    public enum FilterType {
        NEW("New"),
        IN_DESIGN("In Design"),
        AWAITING_APPROVAL("Awaiting approval"),
        ACCEPTED("Accepted"),
        REJECTED("Rejected"),
        OUTDATED("Outdated"),
        TODAY("Today"),
        SUSPECTED_TEST_CASES("Suspected Test Cases"),
        AVG_RATING1("1 - 1.5"),
        AVG_RATING1_5("1.5 - 2.5"),
        AVG_RATING2_5("2.5 - 3.5"),
        AVG_RATING3_5("3.5 - 4.5"),
        AVG_RATING4_5("4.5 - 5"),
        NO_RATING("No rating"),
        RATED_BY_ME("Rated by me"),
        NOT_RATED_BY_ME("Not rated by me"),
        ORPHAN("Orphan"),
        SPECIFIED("Specified");


        private final String text;

        FilterType(String s) {
            text = s;
        }

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

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

    public enum MoreMenuItem {
        CUSTOMIZE("Customize", TrackersCustomizationPage.class, false),
        IMPORT("Import", ImportingItemsPage.class, false),
        EXPORT_TO_OFFICE("Export to Office", ExportToOfficeDialogPage.class, true),
        EXPORT_SELECTION("Export selection (and their children) to Office", ExportToOfficeDialogPage.class, true),
        TEST_COVERAGE("Test Coverage", TestCoveragePage.class, false),
        TRACEABILITY_BROWSER("Traceability Browser", TraceabilityBrowserPage.class, false),
        RISK_MATRIX_DIAGRAM("Risk Matrix Diagram", RiskMatrixDiagramPage.class, false),
        WORKFLOW_DIAGRAM("Workflow Diagram", WorkflowDiagramPage.class, false),
        NEW_VIEW("New View", NewViewPage.class, false),
        SET_AS_DEFAULT("Set as default", null, false),
        CLEAR_DEFAULT("Clear default", null, false),
        DUPLICATE("Duplicate this View", EditViewPage.class, false),
        REFERENCE_VIEW_SETTINGS("Reference View Settings", TrackerItemReferenceConfigurationDialogPage.class, true),
        NEW_BASELINE("New Baseline", NewBaselineDialogPage.class, false),
        SEND_TO_REVIEW("Send to Review", PreviewSelectionStepPage.class, true),
        SEND_SELECTION_TO_REVIEW("Send selection to Review", SendSelectionChooserDialog.class, false),
        LOCK("Lock", DocumentViewPage.class, false),
        UNLOCK("Unlock", DocumentViewPage.class, false),
        FOLLOW("Follow", DocumentViewPage.class, false),
        UNFOLLOW("Unfollow", DocumentViewPage.class, false),
        ADD_TAG("Tags", AddTagDialog.class, true);

        public final String text;
        public final Class<?> pageObjectClass;
        private final boolean isInIframe;

        MoreMenuItem(String s, Class pageObjectClass, boolean isInIframe) {
            text = s;
            this.pageObjectClass = pageObjectClass;
            this.isInIframe = isInIframe;
        }

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

        public boolean isInIframe() {
            return isInIframe;
        }

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

    public void clickOnCenterPaneContextMenuIcon(String itemLabel, int index) {
        centerPaneItem(itemLabel, index).click();
        for (int i = 0; i < 5; ++i) {
            centerPaneItem(itemLabel, index).find(".menuArrowDown").click();
            sleep(1000);//wait for menu to open
            ElementsCollection menuOverlay = $$((By.xpath("//div[normalize-space(@class)='yuimenu' and contains(@style,'display: block')]")));
            if (!menuOverlay.isEmpty()) {
                break;
            }
        }
    }

    public BasePage clickOnCenterPaneContextMenuItem(String itemLabel, int index, CenterPaneContextMenuItem centerPaneContextMenuItem) {
        //first we bring up the menu
        clickOnCenterPaneContextMenuIcon(itemLabel, index);
        //then we find the menu item and click on it
        $(By.xpath("//div[normalize-space(@class)='yuimenu' and contains(@style,'display: block')]//a[contains(text(), '" + centerPaneContextMenuItem.text + "')]")).shouldBe(visible).click();
        return centerPaneContextMenuItem.pageObjectClass != null ? page((Class<BasePage>) centerPaneContextMenuItem.pageObjectClass) : null;
    }

    public void clickOnCenterPaneItem(String itemLabel, int index) {
        centerPaneItem(itemLabel, index).should(exist).click();
    }

    public void clickOnTransitionIcon(String itemLabel, int index) {
        clickOnCompactMode(false);
        centerPaneItem(itemLabel, index).find(By.xpath(".//div[@class='controls']/div[1]")).click();
        sleep(1000);
    }

    public void clickOnTransition(String itemLabel, int index, TransitionType transitionType) {
        clickOnTransitionIcon(itemLabel, index);
        centerPaneItem(itemLabel, index).find(By.xpath(".//div[@class='yuimenu ']//li/a[text()='" + transitionType.text + "']")).click();
    }

    public void clickOnEditDescription(String itemLabel, int index) {
        clickOnCompactMode(false);
        centerPaneItem(itemLabel, index).find(By.xpath(".//div[@class='edit-overlay-container']")).hover().find(".edit-button.edit-description").click();
    }

    public void clickOnEditInWord(String itemLabel, int index) {
        clickOnCompactMode(false);
        centerPaneItem(itemLabel, index).find(By.xpath(".//div[@class='edit-overlay-container']")).hover().find(".edit-button.edit-in-word").click();
    }

    public RatingDialog clickOnRating(String itemLabel, int index) {
        clickOnCompactMode(false);
        centerPaneItem(itemLabel, index).find(By.xpath(".//div[contains(@class, 'rating-container')]")).click();
        return page(RatingDialog.class);
    }

    public AddCommentDialog clickOnComment(String itemLabel, int index) {
        clickOnCompactMode(false);
        centerPaneItem(itemLabel, index).find(By.xpath(".//div[@class='comments']")).click();
        return page(AddCommentDialog.class);
    }

    public void clickOnNewReferringItem(String itemLabel, int index, String option) {
        clickOnCompactMode(false);
        centerPaneItem(itemLabel, index).find(By.xpath(".//div[contains(@class,'referring-items')]")).click();
        $(By.xpath(".//li[@class='context-menu-item' and ./span[contains(.,'" + option + "')]]")).click();
    }

    public void clickOnTestStepExpander(String itemLabel, int index, boolean open) {
        if (open ^ isTestStepsExpanded(itemLabel, index)) {
            centerPaneItem(itemLabel, index).find(By.xpath(".//img[contains(@class, 'expander')]")).click();
            sleep(1000); //TODO change it to wait for indicator to disappear
        }
    }

    public void clickOnEditTestSteps(String itemLabel, int index) {
        centerPaneItem(itemLabel, index).find(By.xpath(".//input[@value='Edit steps']")).click();
    }

    public boolean isFilterSelected(FilterType filterType) {
        $(By.xpath(".//button[contains(@class, 'ui-multiselect')]")).click();
        return $(By.xpath(".//ul[contains(@class, 'ui-multiselect-checkboxes')]//label[@title='" + filterType.text + "']/div[@class='checker checked']")).exists();
    }

    public void selectFilter(FilterType filterType, boolean selected) {
        if (selected ^ isFilterSelected(filterType)) {
            $(By.xpath(".//ul[contains(@class, 'ui-multiselect-checkboxes')]//label[@title='" + filterType.text + "']")).click();
        }
    }

    public boolean isInCompactMode() {
        return centerPane().find(By.xpath(".//div[@class='switch on']")).exists();
    }

    public void clickOnCompactMode(boolean switchToCompactMode) {
        if (isInCompactMode() ^ switchToCompactMode) {
            centerPane().find(By.xpath(".//div[@class='compact-view-mode-switch']")).click();
            //sleep(1000);
        }
    }

    public void clickOnCompactModeInControlBar(String itemLabel, int index) {
        centerPaneItem(itemLabel, index).find(".compact-mode-button").click();
    }

    public void doubleClickOnItem(String itemLabel, int index) {
        centerPaneItem(itemLabel, index).doubleClick();
    }

    public IsPageLoaded clickOnMoreMenuItem(MoreMenuItem moreMenuItem) {
        Wait().withTimeout(10, TimeUnit.SECONDS)
                .pollingEvery(1, TimeUnit.SECONDS)
                .ignoring(NoSuchElementException.class)
                .ignoring(UIAssertionError.class)
                .until((WebDriver driver) -> {
                    moreMenuLink().click();
                    sleep(1000);
                    SelenideElement menu = centerPane().find(By.xpath(".//div[contains(@class,'yuimenu') and contains(@style, 'display: block')]"));
                    if (menu.isDisplayed()) return menu;
                    else
                        return null;
                }).findElement(By.linkText(moreMenuItem.text)).click();
        return moreMenuItem.pageObjectClass != null ? page((Class<IsPageLoaded>) moreMenuItem.pageObjectClass) : null;
    }

    public void clickOnSwitchToHead() {
        centerPane().find(".changeToHeadRevision").click();
    }

    public boolean isLocked() {
        return $(".lockInfo").should(Condition.exist).exists();
    }

    public boolean isUnlocked() {
        return !$(".lockInfo").shouldNot(Condition.exist).exists();
    }


    public void isUnfollowed() {
        moreMenuLink().click();
        $(By.partialLinkText(MoreMenuItem.FOLLOW.text)).should(exist);
    }

    public void isFollowed() {
        moreMenuLink().click();
        $(By.partialLinkText(MoreMenuItem.UNFOLLOW.text)).should(exist);
    }

    public void checkIfFirstTestStepIsFocused(String itemLabel, int index) {
        getAllTestSteps(itemLabel, index).first().find(By.xpath(".//div[contains(@class, 'imagePasteAwareEditor')]")).should(focused);
    }

    private boolean isTestStepsExpanded(String itemLabel, int index) {
        return centerPaneItem(itemLabel, index).find(".expander.noMarginExpander.expanded").isDisplayed();
    }

    public ElementsCollection getAllTestSteps(String itemLabel, int index) {
        return centerPaneItem(itemLabel, index).findAll(By.xpath(".//table[contains(@class,'testStepTable')]/tbody/tr"));
    }

    public int getTestStepCountFromIndicator(String itemLabel, int index) {
        return Integer.parseInt(centerPaneItem(itemLabel, index).find(".testStepCount").getText().split(" ")[0]);
    }

    public boolean isCenterPaneExpandedToLeft() {
        return centerPane().getCssValue("left").equals("1px");
    }

    public boolean isCenterPaneExpandedToRight() {
        //System.out.println($("#centerDiv").getCssValue("right"));
        return centerPane().getCssValue("right").equals("1px");
    }

    public SelenideElement isCenterPaneNotExpandedToRight() {
        return centerPane().shouldNotHave(Helper.css("right", "1px"));
    }

    public boolean isCenterPaneExpandedFully() {
        SelenideElement centerPane = $(".ui-layout-center");
        return centerPane.getCssValue("left").equals("1px") && centerPane.getCssValue("right").equals("0px");
    }

    public boolean isNewTrackerItemEditorInsertedAfter(String itemLabel, int index) {
        return centerPaneItem(itemLabel, index).find(By.xpath("./following-sibling::tr[contains(@id, 'new-item')]")).exists();
    }

    public ElementsCollection getAllCenterPaneItems() {
        return centerPane().findAll(By.xpath("//table[@id='requirements']//tr[.//span[@class='editable']]"));
    }

    public void waitForCenterPaneToLoad() {
        SelenideElement loader = $(By.className("showBusySignDialog"));
        loader.waitUntil(disappears, 4000);
        $("#requirements").shouldBe(visible);
    }

    public void checkIfBlueOverlayVisible(String centerPaneItemName, int centerPaneItemIndex) {
        $(By.xpath("(.//div[@class='document-view-container']//*[@class='name ' and ./span[3 and contains(., '" + centerPaneItemName + "')]])[" + centerPaneItemIndex + "]/following-sibling::div/div[@class='drop-target']"))
                .should(visible.because("Blue overlay is not visible"));
    }

    public void checkIfTransitionMenuVisible(String itemLabel, int index) {
        centerPaneItem(itemLabel, index).find(By.xpath("./td[@class='control-bar']//div[@class='yuimenu ']")).should(visible);
    }

    public void checkIfControlBarIsInCompactMode() {
        centerPane().find(".control-bar.compact").should(exist);
    }

    public void checkIfCompactModePopOverIsVisible(String itemLabel, int index) {
        centerPaneItem(itemLabel, index).find(".controls").should(visible);
    }

    public void checkIfCompactModeIsOn() {
        centerPane().find(By.xpath(".//div[@class='switch on']")).should(exist);
    }

    public void checkIfBaselineInfo(Condition condition) {
        centerPane().find("#docbaselineinfo").shouldBe(condition);

    }

    public void checkIfEditControlOptions(Condition condition) {
        centerPane().find(".edit-overlay-container").shouldBe(condition);
    }

    public void checkIfTransitionMenu(String itemLabel, int index, Condition condition) {
        clickOnTransitionIcon(itemLabel, index);
        $(By.xpath(".//div[contains(@class, 'inlineActionMenu ')]")).shouldBe(condition);
    }

    /**
     * @param itemLabel
     * @param index
     * @param condition visible means we expect to be not editable hidden means otherwise
     */
    public void checkIfSummaryOrDescriptionEditable(String itemLabel, int index, Condition condition) {
        doubleClickOnItem(itemLabel, index);
        SelenideElement dialog = $(By.xpath(".//span[@class='warning' and contains(text(), 'The Summary and the Description of the item are not editable')]//ancestor::div[@role='dialog']"));
        dialog.shouldBe(condition);
        if (Condition.visible.getClass().equals(condition.getClass())) {
            dialog.find(By.xpath(".//button[text()='OK']")).click();
        }
    }

    public void checkIfCenterPanelContextMenuItems(String itemLabel, int index, Condition condition, CenterPaneContextMenuItem... items) {
        clickOnCenterPaneContextMenuIcon(itemLabel, index);
        if (Condition.visible.getClass().equals(condition.getClass())) {
            $$(By.xpath(".//div[@class='yuimenu ' and contains(@style, 'display: block')]//li")).shouldHave(CollectionCondition.size(items.length));
        }
        for (CenterPaneContextMenuItem item : items) {
            $(By.xpath("//div[normalize-space(@class)='yuimenu' and contains(@style,'display: block')]//a[contains(text(), '" + item.text + "')]")).shouldBe(condition);
        }
    }

    public void checkIfMoreMenuItems(Condition condition, boolean exactMatch, MoreMenuItem... moreMenuItems) {
        moreMenuLink().click();
        if (exactMatch && Condition.visible.getClass().equals(condition.getClass())) {
            $$(By.xpath(".//div[contains(@class,'yuimenu') and contains(@style, 'display: block')]//li")).shouldHave(CollectionCondition.size(moreMenuItems.length));
        }
        for (MoreMenuItem moreMenuItem : moreMenuItems) {
            $(By.xpath("//div[contains(@class,'yuimenu') and contains(@style,'display: block')]//a[contains(text(), '" + moreMenuItem.text + "')]")).shouldBe(condition);
        }

    }

    public int getRatingValue(String itemLabel, int index) {
        String classValue = centerPaneItem(itemLabel, index).find(By.xpath(".//div[contains(@class, 'rating-container rated')]")).getAttribute("class");
        Pattern pattern = Pattern.compile("rated-([0-9])");
        Matcher matcher = pattern.matcher(classValue);
        if (matcher.find())
            return Integer.parseInt(matcher.group(1));
        else return -1;
    }
}
