package ru.yandex.autotests.direct.web.pages.banners.blocks.edit.baseblocks;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.hamcrest.Matcher;
import org.junit.Assert;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

import ru.yandex.autotests.direct.utils.config.DirectTestRunProperties;
import ru.yandex.autotests.direct.web.data.banners.ImageLoadType;
import ru.yandex.autotests.direct.web.data.textresources.Strings;
import ru.yandex.autotests.direct.web.objects.banners.BannerInfoWeb;
import ru.yandex.autotests.direct.web.objects.banners.BannerPhraseInfoWeb;
import ru.yandex.autotests.direct.web.objects.banners.commons.ContactInfoWeb;
import ru.yandex.autotests.direct.web.objects.banners.commons.SiteLinkInfoWeb;
import ru.yandex.autotests.direct.web.objects.retargeting.RetargetingConditionWeb;
import ru.yandex.autotests.direct.web.pages.ExtendedHtmlElement;
import ru.yandex.autotests.direct.web.pages.banners.blocks.edit.AddressAndPhoneBlock;
import ru.yandex.autotests.direct.web.pages.banners.blocks.edit.BannerSiteLinksPopupBlock;
import ru.yandex.autotests.direct.web.pages.banners.blocks.edit.RetargetingConditionRow;
import ru.yandex.autotests.direct.web.pages.banners.blocks.edit.bem.ImagePopupSteps;
import ru.yandex.autotests.direct.web.pages.regionselectpopup.RegionSelectPopupBlock;
import ru.yandex.autotests.direct.web.pages.retargeting.blocks.RetargetingPopupBlock;
import ru.yandex.autotests.direct.web.util.DirectWebError;
import ru.yandex.autotests.direct.web.util.JavaScriptActions;
import ru.yandex.autotests.direct.web.util.testinterfaces.IWebFrom;
import ru.yandex.autotests.direct.web.webelements.bem.TextAreaBEM;
import ru.yandex.qatools.htmlelements.annotations.Name;
import ru.yandex.qatools.htmlelements.element.Button;
import ru.yandex.qatools.htmlelements.element.HtmlElement;
import ru.yandex.qatools.htmlelements.element.Link;
import ru.yandex.qatools.htmlelements.element.Select;
import ru.yandex.qatools.htmlelements.element.TextInput;
import ru.yandex.qatools.htmlelements.matchers.WebElementMatchers;

import static ch.lambdaj.Lambda.on;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.not;
import static ru.yandex.autotests.direct.utils.matchers.BeanEquals.beanEquals;
import static ru.yandex.autotests.direct.web.util.WebElementsActions.fillHrefWithScheme;
import static ru.yandex.autotests.direct.web.util.WebElementsActions.getVisibleElement;
import static ru.yandex.autotests.direct.web.util.beanutils.BeanFieldsSetter.inAccordanceWith;
import static ru.yandex.autotests.direct.web.util.beanutils.BeanHelper.hasNotNullProperty;
import static ru.yandex.qatools.htmlelements.matchers.MatcherDecorators.should;
import static ru.yandex.qatools.htmlelements.matchers.MatcherDecorators.timeoutHasExpired;
import static ru.yandex.qatools.htmlelements.matchers.WebElementMatchers.exists;

public abstract class EditBannerBaseBlock extends ExtendedHtmlElement implements IWebFrom<BannerInfoWeb> {

    public final static String BANNER_ID_PREFIX = "Banner-";

    private RetargetingPopupBlock retargetingPopupBlock;

    @FindBy(id = "ChoosedCategories")
    private WebElement choosedRubrics;

    @Name("Ссылка на сайт")
    @FindBy(xpath = ".//input[contains(@class, 'b-banner-form-href__href')]")
    private TextInput href;

    @Name("Селект выбора протокола URL")
    @FindBy(css = "select.b-banner-form-href__protocol")
    private Select hrefProtocolSelect;

    @Name("Ссылка показать/скрыть домен")
    @FindBy(xpath = ".//a[contains(@id, 'a_domain_strict')]")
    private Link domainStrict;

    @Name("Домен")
    @FindBy(xpath = ".//input[contains(@class, 'banner-form-href__domain-input')]")
    private TextInput domain;

    @Name("Заголовок")
    @FindBy(xpath = ".//input[contains(@class, 'b-banner-form__text__title')][not(contains(@class, 'extension'))][@type='text']")
    private TextInput bannerTitle;

    @Name("Заголовок 2")
    @FindBy(xpath = ".//span//input[contains(@class, 'b-banner-form__text__title_extension')]")
    private TextInput bannerTitleExtension;

    @Name("Текст объявления")
    @FindBy(xpath = ".//textarea[contains(@class, 'b-form-input__input b-banner-form__text__body')]")
    private TextAreaBEM bannerBodyText;

    @Name("Открыть попап быстрых ссылок")
    @FindBy(xpath = ".//div[contains(@class, 'b-banner-sitelinks__controls')]//input[@type='button']")
    private WebElement addLinksButton;

    @Name("Текст быстрых ссылок")
    @FindBy(xpath = ".//span[@class='b-banner-sitelinks__text']")
    private WebElement siteLinksText;

    private BannerSiteLinksPopupBlock linksPopupBlock;

    private AddressAndPhoneBlock addressAndPhoneBlock;

    @Name("Выбор регионов показа")
    @FindBy(xpath = ".//span[contains(@class, 'region-select')]/input")
    private WebElement selectRegionButton;

    private List<RegionSelectPopupBlock> regionSelectPopups;

    @Name("Регионы показа")
    @FindBy(xpath = ".//span[@class='b-region-selector__geo-text-fact']")
    private WebElement regionsText;

    @Name("географические идентификаторы регионов")
    @FindBy(xpath = ".//input[contains(@class, 'b-region-selector__geo')]")
    private WebElement regionIDs;

    @Name("Установить минус-слова")
    @FindBy(xpath = ".//div[contains(@class, 'b-minus-words-link')]//input[@type='button']")
    private Button setMinusKeywordsButton;

    @Name("Скрытое поле с минус-словами")
    @FindBy(xpath = ".//input[@class='b-minus-words-link__minus-words']")
    private WebElement minusKeywords;

    @Name("Выбор рубрики")
    @FindBy(xpath = ".//span[contains(@class, 'b-banner-form__rubrics-select-link')]")
    private Link selectRubricFromCatalogLink;

    private List<RetargetingConditionRow> retargetingConditionRows;

    @Name("Добавление условий ретаргетинга")
    @FindBy(xpath = ".//div[contains(@class, 'b-edit-retargeting')]" +
            "//input[preceding-sibling::span/span[text()='" + Strings.BUTTON_ADD + "']]")
    private WebElement addRetargetingCondition;

    @Name("Картинка загрузки")
    @FindBy(xpath = ".//div[@class='b-loader__img']")
    private WebElement conditionsLoaderImage;

    @Name("Сообщение о незаданных условиях ретаргетинга")
    @FindBy(xpath = ".//div[contains(@class, 'conditions-empty')]")
    private WebElement emptyConditionsMessage;

    @Name("Линк показать контактную информацию")
    @FindBy(xpath = ".//span[contains(@class, 'vcard-form-switcher__toggle-link_action_show')]")
    private WebElement showContactInfo;

    @Name("Кнопка изменить изображение")
    @FindBy(xpath = ".//span[contains(@class, 'b-banner-pic__switcher')]/input[@type='button']")
    private WebElement editImageButton;


    private AddressAndPhoneBlock getAddressAndPhoneBlock() {
        addressAndPhoneBlock.setConfig(config);
        return addressAndPhoneBlock;
    }

    public String getHref() {
        return href.getText().equals("") ? "" :
                hrefProtocolSelect.getFirstSelectedOption().getText() + href.getText();
    }

    abstract protected void contactInfoSetEnabled(boolean enabled);

    abstract protected void fillPhrases(BannerPhraseInfoWeb[] phrases);

    protected RetargetingPopupBlock onRetargetingPopup() {
        return retargetingPopupBlock;
    }

    protected void inputTitle(String title) {
        if (title == null) {
            return;
        }
        bannerTitle.clear();
        bannerTitle.sendKeys(title);
    }

    protected void inputTitleExtension(String titleExtension) {
        if (titleExtension == null) {
            return;
        }
        bannerTitleExtension.clear();
        bannerTitleExtension.sendKeys(titleExtension);
    }

    protected void inputText(String text) {
        if (text == null) {
            return;
        }
        bannerBodyText.click();
        bannerBodyText.clear();
        bannerBodyText.sendKeys(text);
    }

    protected void inputHref(String text) {
        fillHrefWithScheme(href, hrefProtocolSelect, text, false);
    }

    protected void fillQuickLinks(SiteLinkInfoWeb[] siteLinks) {
        if (siteLinks == null) {
            return;
        }
        addLinksButton.click();
        linksPopupBlock.fillParameters(siteLinks);
        takeScreenshot();
        linksPopupBlock.clickSave();
    }

    protected void fillContactInfo(ContactInfoWeb contactInfo) {
        if (contactInfo == null) {
            return;
        }
        if (hasNotNullProperty(contactInfo)) {
            contactInfoSetEnabled(true);
            if (WebElementMatchers.isDisplayed().matches(showContactInfo)) {
                showContactInfo.click();
            }
            getAddressAndPhoneBlock().fillParameters(contactInfo);
        } else {
            contactInfoSetEnabled(false);
        }
    }

    protected void fillMinusKeyWords(String[] minusKeyWords) {
        if (minusKeyWords == null) {
            return;
        }
        setMinusKeywordsButton.click();
        minusWordsPopup.textInput.clear();
        minusWordsPopup.textInput.sendKeys(StringUtils.join(minusKeyWords, ", "));
        minusWordsPopup.saveButton.click();
        Assert.assertThat("попап минус слов не соответствует ожиданиям", minusWordsPopup,
                should(anyOf(not(WebElementMatchers.exists()), not(WebElementMatchers.isDisplayed())))
                        .whileWaitingUntil(timeoutHasExpired(TimeUnit.SECONDS.toMillis(
                                DirectTestRunProperties.getInstance()
                                        .getDirectWebWebdriverImplicityWaitTimeoutSec()))));
    }

    protected void fillRegions(String geo) {
        if (geo == null) {
            return;
        }
        new JavaScriptActions(config).scrollToElement(selectRegionButton);
        selectRegionButton.click();
        RegionSelectPopupBlock block = getVisibleElement(regionSelectPopups);
        if (block == null) {
            throw new DirectWebError("Не найден блок редактирования региона");
        }
        block.fillRegions(geo);
    }

    protected void checkSiteLinks(SiteLinkInfoWeb[] siteLinks) {
        if (siteLinks == null) {
            return;
        }
        addLinksButton.click();
        linksPopupBlock.checkParameters(siteLinks);
    }

    protected void checkMinusKeywords(String[] keywords) {
        if (keywords == null) {
            return;
        }
        List<String> actualMinusKeywords =
                Arrays.asList(minusKeywords.getAttribute("value").replace("[\"", "").replace("\"]", "").split("\",\""));
        assertThat("неверно установлены минус-слова", actualMinusKeywords, hasItems(keywords));
    }

    protected void checkContactInfo(ContactInfoWeb contactInfo) {
        if (contactInfo == null) {
            return;
        }
        contactInfoSetEnabled(true);
        getAddressAndPhoneBlock().checkParameters(contactInfo);
    }

    protected String getDomainName() {
        domainStrict.click();
        return domain.getText();
    }

    protected List<RetargetingConditionRow> getRetargetingConditionRows() {
        return retargetingConditionRows;
    }

    protected RetargetingConditionRow getRetargetingConditionRow(String conditionName) {
        for (RetargetingConditionRow row : getRetargetingConditionRows()) {
            if (row.getConditionNameText().equals(conditionName)) {
                return row;
            }
        }
        return null;
    }

    public void clickAddRetargetingCondition() {
        addRetargetingCondition.click();
    }

    public Long getBannerId() {
        return Long.parseLong(this.getAttribute("id").replace(EditBannerBaseBlock.BANNER_ID_PREFIX, ""));
    }

    public String getRegionIDs() {
        return regionIDs.getAttribute("value").replace(" ", "");
    }

    @FindBy(xpath = "//div[contains(@class, 'visible')]//div[contains(@class, 'b-minus-words-popup__content')]")
    private MinusWordsPopup minusWordsPopup;

    public static class MinusWordsPopup extends HtmlElement {
        @Name("")
        @FindBy(xpath = ".//textarea")
        private TextInput textInput;

        @Name("")
        @FindBy(xpath = ".//span[contains(@class, 'button_value_ok')]/input")
        private Button saveButton;
    }

    public void checkMinusKeyWordsPopup(Matcher matcher) {
        assertThat(minusWordsPopup, should(matcher).whileWaitingUntil(
                timeoutHasExpired(TimeUnit.SECONDS.toMillis(
                        DirectTestRunProperties.getInstance().getDirectWebWebdriverImplicityWaitTimeoutSec()))));
    }

    @Override
    public void fillParameters(BannerInfoWeb bannerInfo) {
        config.getDriver().switchTo().window(config.getDriver().getWindowHandle());
        inputTitle(bannerInfo.getTitle());
        inputTitleExtension(bannerInfo.getTitleExtension());
        inputText(bannerInfo.getText());
        inputHref(bannerInfo.getHref());
        fillQuickLinks(bannerInfo.getSitelinks());
        fillContactInfo(bannerInfo.getContactInfo());
        fillPhrases(bannerInfo.getPhrases());

        fillMinusKeyWords(bannerInfo.getMinusKeywords());
        fillRegions(bannerInfo.getGeo());
    }

    @Override
    public void checkParameters(BannerInfoWeb expectedBean) {
        assertThat("неверные параметры баннера ", getFormFieldsAccording(expectedBean), beanEquals(expectedBean));
        checkSiteLinks(expectedBean.getSitelinks());
        checkMinusKeywords(expectedBean.getMinusKeywords());
        checkContactInfo(expectedBean.getContactInfo());
    }

    @Override
    public BannerInfoWeb getFormFieldsAccording(BannerInfoWeb expectedBean) {
        BannerInfoWeb bannerInfo = inAccordanceWith(expectedBean).forNew(BannerInfoWeb.class)
                .set("title", bannerTitle, on(TextInput.class).getText())
                .set("titleExtension", bannerTitleExtension, on(TextInput.class).getText())
                .set("text", bannerBodyText, on(TextAreaBEM.class).getText())
                .set("href", this, on(EditBannerBaseBlock.class).getHref())
                .set("geo", this, on(EditBannerBaseBlock.class).getRegionIDs())
                .set("domain", this, on(EditBannerBaseBlock.class).getDomainName())
                .getActualBean();
        bannerInfo.setBannerId(getBannerId());
        bannerInfo.setCampaignId(expectedBean.getCampaignId());
        bannerInfo.setAdGroupID(expectedBean.getAdGroupID());
        return bannerInfo;
    }

    public void addSavedRetargetingCondition(String conditionName) {
        onRetargetingPopup().clickSavedConditionTab();
        onRetargetingPopup().checkSavedRetargetingCondition(conditionName);
        onRetargetingPopup().clickSave();
        checkRetargetingPopup(not(exists()));
    }

    public void deleteCondition(String conditionName) {
        RetargetingConditionRow conditionRow = getRetargetingConditionRow(conditionName);
        if (conditionRow == null) {
            throw new DirectWebError("Не найдено условие " + conditionName);
        } else {
            conditionRow.clickDelete();
        }
    }

    public void checkRetargetingPopup(Matcher matcher) {
        assertThat("окно ретаргетинга не прошло проверку", onRetargetingPopup(),
                should(matcher).whileWaitingUntil(timeoutHasExpired(TimeUnit.SECONDS.toMillis(30))));
    }

    public void checkCantEditFields(RetargetingConditionWeb conditionWeb) {
        RetargetingConditionRow conditionRow = getRetargetingConditionRow(conditionWeb.getRetargetingConditionName());
        if (conditionRow == null) {
            throw new DirectWebError("Не найдено условие " + conditionWeb.getRetargetingConditionName());
        } else {
            conditionRow.clickOnName();
            onRetargetingPopup().checkRetargetingPopupFields(conditionWeb,
                    ru.yandex.qatools.htmlelements.matchers.
                            WrapsElementMatchers.hasAttribute("disabled", not(equalTo((String) null)))
            );
            onRetargetingPopup().clickCancel();
        }
    }
}

