package ru.yandex.autotests.direct.web.pages.showcampbem.blocks.banners.phrases;

import java.util.List;

import org.hamcrest.Matcher;
import org.openqa.selenium.internal.WrapsElement;
import org.openqa.selenium.support.FindBy;

import ru.yandex.autotests.direct.utils.matchers.BeanEquals;
import ru.yandex.autotests.direct.web.data.banners.MinusKeyWordsTypes;
import ru.yandex.autotests.direct.web.data.priceconstructor.BannerPhrasePlatform;
import ru.yandex.autotests.direct.web.objects.banners.BannerPhraseInfoWeb;
import ru.yandex.autotests.direct.web.objects.retargeting.RetargetingConditionWeb;
import ru.yandex.autotests.direct.web.pages.ExtendedHtmlElement;
import ru.yandex.autotests.direct.web.util.DirectWebError;
import ru.yandex.autotests.direct.web.util.JavaScriptActions;
import ru.yandex.qatools.htmlelements.annotations.Name;
import ru.yandex.qatools.htmlelements.element.TextInput;

import static java.util.stream.Collectors.toList;
import static org.hamcrest.MatcherAssert.assertThat;
import static ru.yandex.autotests.direct.web.util.WebElementsActions.fillTextInput;
import static ru.yandex.autotests.direct.web.util.converters.Banners.toBannerInfo;

/**
 * @author Roman Kuhta (kuhtich@yandex-team.ru)
 * Блок со списком баннеров для устрановки цены клика
 * Присутствует на 2м шаге редактирования баннера и на странице
 * показа баннера
 */
@FindBy(xpath = "./*") //контекст страницы, на которой инициализируется блок
public class BannerPhrasesBlockBEM extends ExtendedHtmlElement {

    //region Fields
    @Name("Фразы для тематических площадок")
    @FindBy(xpath = ".//tr[contains(@class,'b-group-phrase')][@data-bem][ancestor::tbody[contains(@class,'context')]]")
    private List<BannerPhraseRowBlockBEM> phrasesListContext;

    @Name("Фразы для поиска")
    @FindBy(xpath = ".//tr[contains(@class,'b-group-phrase')][@data-bem][ancestor::tbody[contains(@class,'search')]]")
    private List<BannerPhraseRowBlockBEM> phrasesListSearch;

    @Name("Фразы для не независимых стратегий на разных площадках")
    @FindBy(xpath = ".//tr[contains(@class,'b-group-phrase')][@data-bem][ancestor::tbody[contains(@class,'default')]]")
    private List<BannerPhraseRowBlockBEM> phrasesListDefault;

    @Name("Инпут группового изменения ставки на фразы")
    @FindBy(css = ".b-phrases-list-group__price-control_obj-type_phrases input")
    private TextInput groupPriceEditInput;
    //endregion

    //region Field getters
    private List<BannerPhraseRowBlockBEM> getPhrasesListContext() {
        return phrasesListContext;
    }

    private List<BannerPhraseRowBlockBEM> getPhrasesListSearch() {
        return phrasesListSearch;
    }

    private List<BannerPhraseRowBlockBEM> getPhrasesListDefault() {
        return phrasesListDefault;
    }

    private List<BannerPhraseRowBlockBEM> getRowsList(BannerPhrasePlatform platform) {
        switch (platform) {
            case SEARCH:
                return getPhrasesListSearch();
            case CONTEXT:
                return getPhrasesListContext();
            case DEFAULT:
                return getPhrasesListDefault();
        }
        return null;
    }

    private List<BannerPhraseRowBlockBEM> getRowsList(Long bannerId, BannerPhrasePlatform platform) {
        List<BannerPhraseRowBlockBEM> result = getRowsList(platform).stream()
                .filter(bannerPhraseRowBlock -> bannerId.equals(bannerPhraseRowBlock.getAdGroupID()))
                .collect(toList());
        return result;
    }

    private List<BannerPhraseRowBlockBEM> getDeletedPhraseRowsList(BannerPhrasePlatform platform) {
        List<BannerPhraseRowBlockBEM> result = getRowsList(platform).stream()
                .filter(bannerPhraseRowBlock -> bannerPhraseRowBlock.getAttribute("class")
                        .contains("b-group-phrase_deleted_yes"))
                .collect(toList());
        return result;
    }

    //endregion

    //region Actions
    public void fillPhraseParameters(BannerPhraseInfoWeb phraseInfo, BannerPhrasePlatform platform) {
        BannerPhraseRowBlockBEM rowPhrase = getPhraseRow(phraseInfo.getAdGroupID(),
                getPhraseTextFor(phraseInfo), platform);

        if (rowPhrase == null) {
            throw new DirectWebError("Не удалось найти фразу " + getPhraseTextFor(phraseInfo));
        } else {
            rowPhrase.fillParameters(phraseInfo);
        }
    }

    public void fillRetargetingConditionParameters(RetargetingConditionWeb conditionInfo,
            BannerPhrasePlatform platform)
    {
        BannerPhraseRowBlockBEM rowPhrase = getConditionRow(conditionInfo.getAdGroupId(),
                conditionInfo.getRetargetingConditionName(), platform);

        if (rowPhrase == null) {
            throw new DirectWebError("Не удалось найти условие: " + conditionInfo.getRetargetingConditionName());
        } else {
            rowPhrase.fillParameters(conditionInfo);
        }
    }

    public void changePhraseText(BannerPhraseInfoWeb phraseInfo, BannerPhrasePlatform platform, String text) {
        BannerPhraseRowBlockBEM rowPhrase = getPhraseRow(phraseInfo.getAdGroupID(),
                getPhraseTextFor(phraseInfo), platform);

        if (rowPhrase == null) {
            throw new DirectWebError("Не удалось найти фразу " + getPhraseTextFor(phraseInfo));
        } else {
            rowPhrase.fillPhraseText(text);
        }
    }


    //endregion

    //region Assertions
    public void checkMinusKeywordsOnPhrase(Matcher matcher,
            BannerPhrasePlatform platform,
            MinusKeyWordsTypes type,
            BannerPhraseInfoWeb exceptedPhrase)
    {
        BannerPhraseRowBlockBEM block = getPhraseRow(exceptedPhrase.getAdGroupID(),
                getPhraseTextFor(exceptedPhrase), platform);


        if (block == null) {
            throw new DirectWebError("Блок фраз баннера " + exceptedPhrase.getBannerId()
                    + " не найден");
        } else {
            block.checkMinusWords(matcher, type);
        }
    }

    public void checkPhraseParameters(BannerPhrasePlatform platform, BeanEquals<BannerPhraseInfoWeb> matcher) {
        BannerPhraseRowBlockBEM rowPhrase = getPhraseRow(matcher.getExpectedBean().getAdGroupID(),
                getPhraseTextFor(matcher.getExpectedBean()), platform);

        if (rowPhrase == null) {
            throw new DirectWebError("Не удалось найти фразу " + getPhraseTextFor(matcher.getExpectedBean()) +
                    " для платформы " + platform.name());
        } else {
            rowPhrase.checkParameters(matcher);
        }
    }

    public void checkPhraseRowBlock(BannerPhrasePlatform platform, BannerPhraseInfoWeb phrase,
            Matcher matcher)
    {
        BannerPhraseRowBlockBEM rowPhrase = getPhraseRow(phrase.getAdGroupID(),
                getPhraseTextFor(phrase), platform);

        assertThat("фраза не прошла проверку", rowPhrase, matcher);
    }

    public void checkPhrasePrice(BannerPhraseInfoWeb expectedPhrase,
            BannerPhrasePlatform platform,
            Matcher<WrapsElement> matcher)
    {
        BannerPhraseRowBlockBEM rowPhrase = getPhraseRow(expectedPhrase.getAdGroupID(),
                getPhraseTextFor(expectedPhrase), platform);

        if (rowPhrase == null) {
            throw new DirectWebError("Не удалось найти фразу " + getPhraseTextFor(expectedPhrase) + " для платформы " +
                    platform.name());
        } else {
            rowPhrase.checkPrice(expectedPhrase, matcher);
        }
    }

    public void checkRetargetingCondition(BeanEquals<RetargetingConditionWeb> matcher,
            BannerPhrasePlatform platform)
    {
        BannerPhraseRowBlockBEM rowPhrase = getConditionRow(matcher.getExpectedBean().getAdGroupId(),
                matcher.getExpectedBean().getRetargetingConditionName(), platform);
        if (rowPhrase == null) {
            throw new DirectWebError("Не найдено условие " + matcher.getExpectedBean().getRetargetingConditionName());
        } else {
            RetargetingConditionWeb actualCondition = rowPhrase.getRetargetingCondition(matcher.getExpectedBean());
            assertThat("неверные параметры условия ретаргетинга", actualCondition, matcher);
        }
    }

    public void checkPhrasesMinusKeyWordPopupText(Long bannerId, BannerPhrasePlatform platform, Matcher matcher) {
        List<BannerPhraseRowBlockBEM> list = getRowsList(bannerId, platform);
        for (BannerPhraseRowBlockBEM row : list) {
            row.checkPhraseMinusKeyWordPopupText(matcher);
        }
    }

    public void checkPriceInputErrorHighlight(BannerPhraseInfoWeb phraseInfo, BannerPhrasePlatform platform,
            Matcher<Boolean> matcher)
    {
        BannerPhraseRowBlockBEM rowPhrase = getPhraseRow(phraseInfo.getAdGroupID(),
                getPhraseTextFor(phraseInfo), platform);

        if (rowPhrase == null) {
            throw new DirectWebError("Не удалось найти фразу " + getPhraseTextFor(phraseInfo));
        } else {
            rowPhrase.checkPriceInputErrorHighlight(matcher);
        }
    }

    //endregion

    private String getPhraseTextFor(BannerPhraseInfoWeb phraseInfo) {
        return phraseInfo.getPhrase().replace("+", "");
    }

    private BannerPhraseRowBlockBEM getPhraseRow(Long adGroupID, String phraseText, BannerPhrasePlatform platform) {
        for (BannerPhraseRowBlockBEM bannerPhraseRowBlock : getRowsList(platform)) {
            if (!adGroupID.equals(bannerPhraseRowBlock.getAdGroupID())) {
                continue;
            }
            if (phraseText.equals(bannerPhraseRowBlock.getPhraseText())) {
                bannerPhraseRowBlock.setConfig(config);
                new JavaScriptActions(config).scrollToElement(bannerPhraseRowBlock.getWrappedElement());
                return bannerPhraseRowBlock;
            }
        }
        return null;
    }

    private BannerPhraseRowBlockBEM getRestorePhraseRow(String phraseId, BannerPhrasePlatform platform) {
        for (BannerPhraseRowBlockBEM bannerPhraseRowBlock : getDeletedPhraseRowsList(platform)) {
            if (bannerPhraseRowBlock.getAttribute("data-bem").contains(phraseId)) {
                new JavaScriptActions(config).scrollToElement(bannerPhraseRowBlock.getWrappedElement());
                return bannerPhraseRowBlock;
            }
        }
        return null;
    }

    private BannerPhraseRowBlockBEM getConditionRow(Long adGroupID, String phraseText, BannerPhrasePlatform platform) {
        for (BannerPhraseRowBlockBEM bannerPhraseRowBlock : getRowsList(platform)) {
            if (!adGroupID.equals(bannerPhraseRowBlock.getAdGroupID())) {
                continue;
            }
            if (phraseText.equals(bannerPhraseRowBlock.getRetargetingName())) {
                bannerPhraseRowBlock.setConfig(config);
                new JavaScriptActions(config).scrollToElement(bannerPhraseRowBlock.getWrappedElement());
                return bannerPhraseRowBlock;
            }
        }
        return null;
    }

    public BannerPhraseInfoWeb getPhaseInfo(BannerPhraseInfoWeb expectedPhrase, BannerPhrasePlatform platform) {
        BannerPhraseRowBlockBEM rowPhrase = getPhraseRow(expectedPhrase.getAdGroupID(),
                getPhraseTextFor(expectedPhrase), platform);

        if (rowPhrase == null) {
            throw new DirectWebError("Не удалось найти фразу " + getPhraseTextFor(expectedPhrase));
        } else {
            return rowPhrase.getFormFieldsAccording(expectedPhrase);
        }
    }

    public void deleteRetargetingCondition(BannerPhrasePlatform platform, RetargetingConditionWeb conditionWeb) {
        deletePhrase(platform, toBannerInfo(conditionWeb));
    }

    public void deletePhrase(BannerPhrasePlatform platform, BannerPhraseInfoWeb phraseInfo) {
        BannerPhraseRowBlockBEM rowPhrase = getPhraseRow(phraseInfo.getAdGroupID(),
                getPhraseTextFor(phraseInfo), platform);

        if (rowPhrase == null) {
            throw new DirectWebError("Не удалось найти фразу " + getPhraseTextFor(phraseInfo));
        } else {
            rowPhrase.deleteCondition();
        }
    }

    public void clickRefinePhrase(BannerPhrasePlatform platform, BannerPhraseInfoWeb phraseInfo) {
        BannerPhraseRowBlockBEM rowPhrase = getPhraseRow(phraseInfo.getAdGroupID(),
                getPhraseTextFor(phraseInfo), platform);
        if (rowPhrase == null) {
            throw new DirectWebError("Не удалось найти фразу " + getPhraseTextFor(phraseInfo));
        } else {
            new JavaScriptActions(config).scrollToElement(rowPhrase.getWrappedElement());
            rowPhrase.clickRefinePhrase();
        }
    }

    public void restorePhrase(BannerPhrasePlatform platform, BannerPhraseInfoWeb phraseInfo) {
        BannerPhraseRowBlockBEM rowPhrase = getRestorePhraseRow(String.valueOf(phraseInfo.getPhraseID()), platform);
        if (rowPhrase == null) {
            throw new DirectWebError("Не удалось найти фразу " + getPhraseTextFor(phraseInfo));
        } else {
            rowPhrase.restore();
        }
    }

    public void setPriceForALlPhrasesInGroup(String value) {
        fillTextInput(groupPriceEditInput, value);
        new JavaScriptActions(config).fireBlurEvent(groupPriceEditInput.getWrappedElement());
    }

    public BannerPhraseRowBlockBEM getSocDemRow(Long adGroupId) {
        return phrasesListContext.stream()
                .filter(pr -> pr.getAdGroupID().equals(adGroupId))
                .findFirst()
                .orElseThrow(() -> new DirectWebError("Не найдена группа с ID:" + adGroupId));
    }
}