package com.atlassian.webdriver.bitbucket.element;

import com.atlassian.pageobjects.Page;
import com.atlassian.pageobjects.component.Header;
import com.atlassian.pageobjects.component.WebSudoBanner;
import com.atlassian.pageobjects.elements.PageElement;
import com.atlassian.webdriver.bitbucket.page.LogoutPage;
import com.atlassian.webdriver.bitbucket.page.BitbucketLoginPage;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

import javax.annotation.Nonnull;
import javax.inject.Inject;

import static com.google.common.base.Preconditions.checkNotNull;


public class BitbucketHeader extends AbstractElementPageObject implements Header {

    @Inject
    protected WebDriver driver;

    public BitbucketHeader(@Nonnull PageElement pageElement) {
        super(pageElement);
    }

    public UserDropdown getUserDropdown() {
        return getGlobal().getSecondary().getUserDropdown();
    }

    public LinkElement getHelpLink() {
        return getGlobal().getSecondary().getHelpLink();
    }

    public RecentReposDropdown getRecentReposDropdown() {
        return getGlobal().getPrimary().getRecentReposDropdown();
    }

    public AppSwitcherDropdown getAppSwitcher() {
        return pageBinder.bind(AppSwitcherDropdown.class, find(By.className("app-switcher-trigger")));
    }

    @Override
    public boolean isLoggedIn() {
        return !driver.getCurrentUrl().contains("/login") && getUserDropdown().isLoggedIn();
    }

    public BitbucketLoginPage login() {
        find(By.id("login-link")).click();
        return pageBinder.bind(BitbucketLoginPage.class, false);
    }

    @Override
    public <M extends Page> M logout(Class<M> nextPage) {
        getUserDropdown().clickTrigger().clickLogout();
        return LogoutPage.class.isAssignableFrom(nextPage) ? pageBinder.bind(nextPage) : pageBinder.navigateToAndBind(nextPage);
    }

    @Override
    public WebSudoBanner getWebSudoBanner() {
        throw new UnsupportedOperationException();
    }

    private HeaderGlobal getGlobal() {
        return pageBinder.bind(HeaderGlobal.class, find(By.className("aui-header")));
    }

    public static class HeaderGlobal extends HeaderSection<GlobalPrimary, GlobalSecondary> {

        public HeaderGlobal(@Nonnull PageElement container) {
            super(container, GlobalPrimary.class, GlobalSecondary.class);
        }
    }

    public static class GlobalPrimary extends AbstractElementPageObject {

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

        public RecentReposDropdown getRecentReposDropdown() {
            return pageBinder.bind(RecentReposDropdown.class);
        }
    }

    public static class GlobalSecondary extends AbstractElementPageObject {

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

        public UserDropdown getUserDropdown() {
            return pageBinder.bind(UserDropdown.class, find(By.className("user-dropdown")));
        }

        public LinkElement getHelpLink() {
            return pageBinder.bind(LinkElement.class, find(By.className("help-link")));
        }
    }

    public abstract static class HeaderSection<P extends AbstractElementPageObject, S extends AbstractElementPageObject>
            extends AbstractElementPageObject {

        private final Class<P> primaryClass;
        private final Class<S> secondaryClass;

        protected HeaderSection(@Nonnull PageElement container, @Nonnull Class<P> primaryClass,
                                @Nonnull Class<S> secondaryClass) {
            super(container);
            this.primaryClass = checkNotNull(primaryClass, "primaryClass");
            this.secondaryClass = checkNotNull(secondaryClass, "secondaryClass");
        }

        public P getPrimary() {
            return pageBinder.bind(primaryClass, find(By.className("aui-header-primary")));
        }

        public S getSecondary() {
            return pageBinder.bind(secondaryClass, find(By.className("aui-header-secondary")));
        }
    }
}
