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

import org.hamcrest.Matcher;
import org.openqa.selenium.WebElement;
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.TestEnvironment;
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.beanutils.BeanFieldsSetter;
import ru.yandex.qatools.htmlelements.annotations.Name;
import ru.yandex.qatools.htmlelements.matchers.WebElementMatchers;

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

import static ch.lambdaj.Lambda.on;
import static org.hamcrest.MatcherAssert.assertThat;
import static ru.yandex.autotests.direct.web.util.beanutils.BeanFieldsSetter.inAccordanceWith;
import static ru.yandex.qatools.htmlelements.matchers.MatcherDecorators.should;
import static ru.yandex.qatools.htmlelements.matchers.MatcherDecorators.timeoutHasExpired;

/**
 * @author Roman Kuhta (kuhtich@yandex-team.ru)
 *         Блок со списком баннеров для устрановки цены клика
 *         Присутствует на странице медиаплана, вкладке медиаплана и вкладке первой помощи на странице кампании
 *         (в других местах BannerPhrasesBlockBEM)
 */
@FindBy(xpath = ".//ul[contains(@class, 'b-banner-list')]")
public class BannerPhrasesBlock extends ExtendedHtmlElement {

    private List<BannerPhraseRowBlock> phrasesList;

    @Name("Показать отключенные фразы")
    @FindBy(xpath = ".//span[contains(@class, 'closable-inactive')]")
    private WebElement showSwitchedOffPhrases;

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

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

    @Name("Фразы для автобюджетных стратегий")
    @FindBy(xpath = ".//tr[contains(@class, 'b-phrases-list__phrase')][ancestor::tbody[contains(@class, 'auto')]]")
    private List<BannerPhraseRowBlock> phrasesListAuto;

    private List<BannerPhraseRowBlock> getRowsList(BannerPhrasePlatform platform) {
        switch (platform) {
            case SEARCH:
                return phrasesListSearch;
            case CONTEXT:
                return phrasesListContext;
            case DEFAULT:
                return phrasesListAuto;
            case MEDIAPLAN:
                return phrasesList;
        }
        return null;
    }

    private BannerPhraseRowBlock getPhraseRow(Long bannerId, String phraseText, BannerPhrasePlatform platform) {
        for (BannerPhraseRowBlock bannerPhraseRowBlock : getRowsList(platform)) {
            if (!bannerId.equals(bannerPhraseRowBlock.getBannerId()))
                continue;
            if (phraseText.equals(bannerPhraseRowBlock.getPhrase())) {
                bannerPhraseRowBlock.setConfig(config);
                return bannerPhraseRowBlock;
            }
        }
        return null;
    }

    private BannerPhraseRowBlock getFirstPhraseRow(BannerPhrasePlatform platform) {
        BannerPhraseRowBlock result = null;
        if (getRowsList(platform).size() > 0) {
            result = getRowsList(platform).get(0);
        }
        if (result != null) {
            result.setConfig(config);
        }
        return result;
    }

    private List<BannerPhraseRowBlock> getPhrasesRows(Long bannerId, BannerPhrasePlatform platform,
                                                      List<String> phraseTexts) {
        List<BannerPhraseRowBlock> list = new ArrayList<>();
        for (BannerPhraseRowBlock bannerPhraseRowBlock : getRowsList(platform)) {
            if (!bannerId.equals(bannerPhraseRowBlock.getBannerId())) {
                continue;
            }
            if (phraseTexts.contains(bannerPhraseRowBlock.getPhrase())) {
                bannerPhraseRowBlock.setConfig(config);
                list.add(bannerPhraseRowBlock);
            }
        }
        return list;
    }

    private List<BannerPhraseRowBlock> getPhrasesRows(Long bannerId, BannerPhrasePlatform platform) {
        List<BannerPhraseRowBlock> phraseList = new ArrayList<>();
        for (BannerPhraseRowBlock bannerPhraseRowBlock : getRowsList(platform)) {
            if (!bannerId.equals(bannerPhraseRowBlock.getBannerId()))
                continue;
            bannerPhraseRowBlock.setConfig(config);
            phraseList.add(bannerPhraseRowBlock);
        }
        return phraseList;
    }

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

    private void fillPhrasePriority(BannerPhraseInfoWeb phraseInfo) {
        BannerPhraseRowBlock rowPhrase = getPhraseRow(phraseInfo.getBannerId(),
                getPhraseTextFor(phraseInfo), BannerPhrasePlatform.DEFAULT);
        if (rowPhrase == null)
            return;
        rowPhrase.selectPriority(phraseInfo.getAutoBudgetPriority());
    }

    private void fillPhraseSearchPrice(BannerPhraseInfoWeb phraseInfo) {
        BannerPhraseRowBlock rowPhrase = getPhraseRow(phraseInfo.getBannerId(),
                getPhraseTextFor(phraseInfo), BannerPhrasePlatform.SEARCH);
        if (rowPhrase == null)
            return;
        if (phraseInfo.getPrice() != null) {
            rowPhrase.fillSearchPrice(phraseInfo.getPrice());
        }
    }

    private void fillPhraseContextPrice(BannerPhraseInfoWeb phraseInfo) {
        BannerPhraseRowBlock rowPhrase = getPhraseRow(phraseInfo.getBannerId(),
                getPhraseTextFor(phraseInfo), BannerPhrasePlatform.CONTEXT);
        if (rowPhrase == null)
            return;
        if (phraseInfo.getContextPrice() != null) {
            rowPhrase.fillContextPrice(phraseInfo.getContextPrice());
        }
    }

    private void fillRetargetingPrice(RetargetingConditionWeb retargeting, BannerPhrasePlatform platform) {
        BannerPhraseRowBlock rowPhrase = getPhraseRow(retargeting.getBannerId(),
                retargeting.getRetargetingConditionName(), platform);
        if (rowPhrase == null)
            return;
        rowPhrase.fillContextPrice(retargeting.getContextPrice());
    }

    private void fillRetargetingPriority(RetargetingConditionWeb retargeting) {
        BannerPhraseRowBlock rowPhrase = getPhraseRow(retargeting.getBannerId(),
                retargeting.getRetargetingConditionName(), BannerPhrasePlatform.DEFAULT);
        if (rowPhrase == null)
            return;
        rowPhrase.selectPriority(retargeting.getAutoBudgetPriority());
    }

    public void fillPhraseParameters(BannerPhraseInfoWeb phraseInfo, BannerPhrasePlatform platform) {
        switch (platform) {
            case SEARCH:
                fillPhraseSearchPrice(phraseInfo);
                break;
            case CONTEXT:
                fillPhraseContextPrice(phraseInfo);
                break;
            case DEFAULT:
                fillPhrasePriority(phraseInfo);
                break;
        }
    }

    public void fillRetargetingParameters(RetargetingConditionWeb retargeting, BannerPhrasePlatform platform) {
        switch (platform) {
            case MEDIAPLAN:
            case CONTEXT:
                fillRetargetingPrice(retargeting, platform);
                break;
            case DEFAULT:
                fillRetargetingPriority(retargeting);
                break;
        }
    }

    private BannerPhraseInfoWeb getRowPhraseInfo(BannerPhraseRowBlock rowPhrase, BannerPhraseInfoWeb expectedPhrase,
                                                 BannerPhrasePlatform platform) {
        BannerPhraseInfoWeb result = new BannerPhraseInfoWeb();
        if (rowPhrase == null)
            return result;

        BeanFieldsSetter<BannerPhraseInfoWeb> setter =
                inAccordanceWith(expectedPhrase).forNew(BannerPhraseInfoWeb.class);
        switch (platform) {
            case MEDIAPLAN:
                //TODO костыль, который нужно будет убрать при переделывании работы под трафаретные торги
                //сейчас подставляем дефолтное значение, но по-хорошему оно должно считываться со страницы
                result = setter.set("trafficVolumeForecast", rowPhrase, on(BannerPhraseRowBlock.class).getTrafficForecast())
                        .getActualBean();
                break;

            case SEARCH:
                result = setter.set("price", rowPhrase, on(BannerPhraseRowBlock.class).getSearchPrice())
                        .set("min", rowPhrase, on(BannerPhraseRowBlock.class).getPriceGuaranty())
                        .set("max", rowPhrase, on(BannerPhraseRowBlock.class).getPriceGuarantyFirst())
                        .set("premiumMin", rowPhrase, on(BannerPhraseRowBlock.class).getPriceSpecialPlace())
                        .set("premiumMax", rowPhrase, on(BannerPhraseRowBlock.class).getPriceSpecialPlaceFirst())
                        .set("currentOnSearch", rowPhrase, on(BannerPhraseRowBlock.class).getPriceOnSearch())
                        .set("state", rowPhrase, on(BannerPhraseRowBlock.class).getState())
                        .set("trafficVolumeForecast", rowPhrase, on(BannerPhraseRowBlock.class).getTrafficForecast())
                        .getActualBean();
                break;
            case CONTEXT:
                result = setter.set("contextPrice", rowPhrase, on(BannerPhraseRowBlock.class).getContextPrice())
                        .set("state", rowPhrase, on(BannerPhraseRowBlock.class).getState())
                        .getActualBean();
                break;
            case DEFAULT:
                result = setter.set("autoBudgetPriority", rowPhrase, on(BannerPhraseRowBlock.class).getPriorityValue())
                        .getActualBean();
                break;
        }
        result.setPhrase(expectedPhrase.getPhrase());
        result.setBannerId(expectedPhrase.getBannerId());

        return result;
    }

    public BannerPhraseInfoWeb getPhraseInfo(BannerPhraseInfoWeb expectedPhrase, BannerPhrasePlatform platform) {
        BannerPhraseRowBlock rowPhrase = getPhraseRow(expectedPhrase.getBannerId(),
                getPhraseTextFor(expectedPhrase), platform);
        return getRowPhraseInfo(rowPhrase, expectedPhrase, platform);
    }

    public void checkPhraseParameters(BannerPhrasePlatform platform, BeanEquals<BannerPhraseInfoWeb> matcher) {
        BannerPhraseInfoWeb actualPhrase = getPhraseInfo(matcher.getExpectedBean(), platform);
        assertThat("неверные параметры фразы " + matcher.getExpectedBean().getPhrase(), actualPhrase, should(matcher).
                whileWaitingUntil(timeoutHasExpired(TimeUnit.SECONDS.toMillis(TestEnvironment.getDirectWebProperties().
                        getImplicitWait()))));
    }

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

    public void declinePhrase(Long bannerId, String phraseText) {
        BannerPhraseRowBlock row = getPhraseRow(bannerId, phraseText, BannerPhrasePlatform.MEDIAPLAN);
        if (row == null) {
            throw new DirectWebError("Не найдена фраза '" + phraseText + "'");
        } else {
            row.deselectPhrase();
        }
    }

    public void checkClientDeclinePhrase(Long bannerId, String phraseText) {
        BannerPhraseRowBlock row = getPhraseRow(bannerId, phraseText, BannerPhrasePlatform.MEDIAPLAN);
        if (row == null) {
            throw new DirectWebError("Не найдена фраза '" + phraseText + "'");
        } else {
            row.checkClientDecline();
        }
    }

    public void selectPhrasesByText(Long bannerId, BannerPhrasePlatform platform, String... phraseTexts) {
        List<BannerPhraseRowBlock> list = getPhrasesRows(bannerId, platform, java.util.Arrays.asList(phraseTexts));
        for (BannerPhraseRowBlock row : list) {
            row.selectPhrase();
        }
    }

    public void checkBannerPhraseRowBlock(Long bannerId, String phraseText, BannerPhrasePlatform platform,
                                          Matcher matcher) {
        BannerPhraseRowBlock row = getPhraseRow(bannerId, phraseText, platform);
        assertThat("блок с фразой не соответствует ожиданиям", row, matcher);
    }

    public void checkPhrasePrice(BannerPhraseInfoWeb expectedPhrase,
                                 BannerPhrasePlatform platform,
                                 Matcher<WrapsElement> matcher,
                                 int index) {
        List<BannerPhraseRowBlock> rows = new ArrayList<>();
        for (BannerPhraseRowBlock bannerPhraseRowBlock : getRowsList(platform)) {
            if (!String.valueOf(expectedPhrase.getBannerId()).equals(bannerPhraseRowBlock.getBannerId()))
                continue;
            if (getPhraseTextFor(expectedPhrase).equals(bannerPhraseRowBlock.getPhrase())) {
                rows.add(bannerPhraseRowBlock);
            }
        }
        BannerPhraseRowBlock rowPhrase = rows.get(index);
        rowPhrase.checkPrice(expectedPhrase, platform, matcher);
    }

    public void showInactive() {
        if (WebElementMatchers.isDisplayed().matches(showSwitchedOffPhrases)) {
            showSwitchedOffPhrases.click();
        }
    }
}
