package ru.yandex.autotests.direct.web.pages.group;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

import ru.yandex.autotests.direct.web.objects.adjustment.rates.HierarchicalMultipliersWeb;
import ru.yandex.autotests.direct.web.objects.groups.BaseGroupWeb;
import ru.yandex.autotests.direct.web.objects.groups.feedfilter.DynamicFeedFilter;
import ru.yandex.autotests.direct.web.objects.groups.feedfilter.FeedFilterBase;
import ru.yandex.autotests.direct.web.objects.groups.feedfilter.PerformanceFeedFilter;
import ru.yandex.autotests.direct.web.pages.ExtendedHtmlElement;
import ru.yandex.autotests.direct.web.pages.adjustment.blocks.AdjustmentRatesPopupBlock;
import ru.yandex.autotests.direct.web.pages.banners.blocks.edit.bem.BannerBlockBEM;
import ru.yandex.autotests.direct.web.pages.banners.blocks.edit.bem.MinusWordsPopupBEM;
import ru.yandex.autotests.direct.web.pages.group.blocks.EditFilterBlockBase;
import ru.yandex.autotests.direct.web.pages.group.blocks.FilterItem;
import ru.yandex.autotests.direct.web.pages.group.dynamictext.EditDynamicFilterBlock;
import ru.yandex.autotests.direct.web.pages.group.performance.EditPerformanceFilterBlock;
import ru.yandex.autotests.direct.web.pages.regionselectpopup.RegionSelectPopupBlockBEM;
import ru.yandex.autotests.direct.web.util.DirectWebError;
import ru.yandex.qatools.htmlelements.annotations.Name;
import ru.yandex.qatools.htmlelements.element.Button;
import ru.yandex.qatools.htmlelements.element.TextInput;
import ru.yandex.qatools.htmlelements.matchers.WebElementMatchers;

import static ch.lambdaj.Lambda.on;
import static java.lang.Long.parseLong;
import static java.util.Objects.isNull;
import static java.util.stream.Collectors.toList;
import static org.hamcrest.Matchers.not;
import static ru.yandex.autotests.direct.web.steps.CommonSteps.waitForElement;
import static ru.yandex.autotests.direct.web.util.WebElementsActions.waitVisibility;
import static ru.yandex.autotests.direct.web.util.beanutils.BeanFieldsSetter.inAccordanceWith;

/**
 * Created by ssdmitriev on 25.11.15.
 */
public abstract class GroupBaseBlock extends ExtendedHtmlElement {
    public final static String NEW_AD_GROUP_ID = "new";
    public final static String FIRST_NEW_AD_GROUP_ID = "new1";

    protected List<FilterItem> filterItems;

    @Name("Инпут 'Название группы'")
    @FindBy(xpath = ".//span[contains(@class, 'name-input')]//input")
    private TextInput groupName;

    @Name("Блок с id группы")
    @FindBy(xpath = ".//div[contains(@class, 'b-edit-group__rename-group')]")
    private WebElement groupID;

    @Name("Кнопка 'задать' минус-слова")
    @FindBy(xpath = ".//div[contains(@class, 'b-minus-words-control')]//button")
    private Button setMinusWordsButton;

    @Name("Попав для минус слов")
    private MinusWordsPopupBEM minusKeywordsPopup;

    @Name("Кнопка 'уточнить' регионы показа")
    @FindBy(xpath = ".//div[contains(@class, 'b-regions')]//button")
    private Button setGeoTags;

    @Name("Попав для регионов показа")
    private RegionSelectPopupBlockBEM geoTagsPopup;

    @Name("Кнопка 'задать' метки")
    @FindBy(xpath = ".//div[contains(@class, 'b-group-tags')]//button")
    private Button setTags;

    @Name("Попап для тэгов")
    @FindBy(xpath = "//div[contains(@class, 'b-group-tags2-edit ')]")
    private TagsPopup tagsPopup;

    @Name("Попап для корректировки ставок")
    private AdjustmentRatesPopupBlock adjustmentRatesPopupBlock;

    @Name("Кнопка 'изменить' корректировки ставок")
    @FindBy(xpath = ".//div[@class = 'b-adjustment-rates-popup__rates']/preceding-sibling::button")
    private Button setAdjustment;

    @Name("Добавить фильтр")
    @FindBy(xpath = ".//div[contains(@class, 'filters__add-control')]//button")
    private Button addFilter;

    private List<GroupFilterBlockBEM> filtersBlockBEM;
    private List<BannerBlockBEM> bannerBlockBEMs;

    private List<GroupFilterBlockBEM> getFiltersBlocks() {
        return filtersBlockBEM;
    }

    private void fillAdjustmentRatesPopupBlock(HierarchicalMultipliersWeb hierarchicalMultipliersWeb) {
        if (hierarchicalMultipliersWeb == null) {
            return;
        }
        setAdjustment.click();
        waitVisibility(adjustmentRatesPopupBlock);
        adjustmentRatesPopupBlock.fillParameters(hierarchicalMultipliersWeb);
    }

    public void checkHierarchicalMultipliersParameters(HierarchicalMultipliersWeb hierarchicalMultipliers) {
        setAdjustment.click();
        waitVisibility(adjustmentRatesPopupBlock);
        adjustmentRatesPopupBlock.checkParameters(hierarchicalMultipliers);
        adjustmentRatesPopupBlock.clickCancel();
    }

    public HierarchicalMultipliersWeb getAdjustmentRatesPopupBlock(HierarchicalMultipliersWeb hierarchicalMultipliersWeb) {
        setAdjustment.click();
        waitVisibility(adjustmentRatesPopupBlock);
        HierarchicalMultipliersWeb result = adjustmentRatesPopupBlock.getHierarchicalMultipliersWeb(hierarchicalMultipliersWeb);
        adjustmentRatesPopupBlock.clickCancel();
        return result;
    }

    public Long getGroupId() {
        String data = this.getAttribute("data-bem");
        Pattern pattern = Pattern.compile("\"modelId\":[-0-9a-zA-Z\"]*");
        java.util.regex.Matcher matcher = pattern.matcher(data);
        String result = null;
        if (matcher.find()) {
            result = matcher.group().replaceAll("[\":]", "").replace("modelId", "");
        }
        //для совместимости с бинами (в них хранится 0 в поле bannerId для нового баннера)
        if (NEW_AD_GROUP_ID.equals(result) || FIRST_NEW_AD_GROUP_ID.equals(result)) {
            result = "0";
        }
        return isNull(result) ? null : parseLong(result);
    }


    private void fillGroupName(String name) {
        if (name == null) {
            return;
        }
        groupName.clear();
        groupName.sendKeys(name);
    }

    public String getGroupName() {
        return groupName.getText();
    }

    public void fillMinusKeyWords(List<String> minusKeywords) {
        if (minusKeywords == null) {
            return;
        }
        setMinusWordsButton.click();
        waitVisibility(minusKeywordsPopup);
        minusKeywordsPopup.setConfig(config);
        minusKeywordsPopup.fillMinusKeywordsTextInput(minusKeywords.toArray(new String[minusKeywords.size()]));
        minusKeywordsPopup.clickOnSaveButton();
    }

    public void fillRegionsAndExpectSuccess(List<String> newTags) {
        fillRegions(newTags);
        waitForElement(geoTagsPopup.getWrappedElement(), 5, not(WebElementMatchers.isDisplayed()));
    }

    public void fillRegions(List<String> newTags) {
        if (newTags == null) {
            return;
        }
        setGeoTags.click();
        waitVisibility(geoTagsPopup);
        geoTagsPopup.clearAllRegions();
        geoTagsPopup.fillRegions(newTags);
    }

    private void fillTags(String[] newTags) {
        if (newTags == null) {
            return;
        }
        setTags.click();
        waitVisibility(tagsPopup);
        tagsPopup.fillTags(newTags);
        tagsPopup.clickOnSaveButton();
    }

    public String getTags() {
        setTags.click();
        waitVisibility(tagsPopup);
        String result = tagsPopup.getTags();
        tagsPopup.clickOnCancelButton();
        return result;
    }

    public List<String> getGeoTags() {
        setGeoTags.click();
        waitVisibility(geoTagsPopup);
        List<String> result = geoTagsPopup.getSelectedRegions();
        geoTagsPopup.clickOnCancelButton();
        return result;
    }

    public List<String> getMinusKeyWords() {
        setMinusWordsButton.click();
        waitVisibility(minusKeywordsPopup);
        return minusKeywordsPopup.getMinusWords();
    }

    public void fillParameters(BaseGroupWeb bean) {
        if (bean == null) {
            return;
        }
        fillGroupName(bean.getAdGroupName());
        fillRegionsAndExpectSuccess(bean.getGeoTags());
        fillMinusKeyWords(bean.getMinusKeywords());
        if (bean.getTags() != null) {
            fillTags(bean.getTags().split(" "));
        }
        fillAdjustmentRatesPopupBlock(bean.getHierarchicalMultipliersWeb());
    }


    public BaseGroupWeb getBean(BaseGroupWeb expectedBean) {
        return inAccordanceWith(expectedBean).forNew(BaseGroupWeb.class)
                .set("adGroupId", this, on(GroupBaseBlock.class).getGroupId())
                .set("adGroupName", this, on(GroupBaseBlock.class).getGroupName())
                .set("geoTags", this, on(GroupBaseBlock.class).getGeoTags())
                .set("hierarchicalMultipliersWeb", this, on(GroupBaseBlock.class).getAdjustmentRatesPopupBlock(expectedBean.getHierarchicalMultipliersWeb()))
                .set("minusKeywords", this, on(GroupBaseBlock.class).getMinusKeyWords())
                .set("tags", this, on(GroupBaseBlock.class).getTags())
                .getActualBean();
    }

    private GroupFilterBlockBEM getFilterBlockByName(String filtersName) {
        GroupFilterBlockBEM block = getFiltersBlocks().stream()
                .filter(t -> filtersName.equals(t.getFiltersName().toString()))
                .findFirst().orElseThrow(() -> new DirectWebError("Не найден фильтр: " + filtersName));
        block.setConfig(config);
        return block;
    }

    public void openFilterPopup(String filtersName) {
        getFilterBlockByName(filtersName).clickEditFilterButton();
    }

    protected void clickAddFilter() {
        addFilter.click();
    }

    protected void fillFilter(List<? extends FeedFilterBase> feedFilters) {
        if (feedFilters == null) {
            return;
        }
        List<String> filterIds = feedFilters.stream()
                .filter(t -> t.getFilterId() != null)
                .map(FeedFilterBase::getFilterId)
                .collect(toList());

        //Удаляем фильтры, которые есть на странице, но нет в бине
        filterItems.stream()
                .filter(t -> !filterIds.contains(t.getFilterId()))
                .forEach(FilterItem::clickRemoveButton);

        //Редактируем фильтры
        filterItems.stream()
                .filter(t -> filterIds.contains(t.getFilterId()))
                .forEach(t -> editFilter(t, feedFilters.stream()
                        .filter(f -> f.getFilterId().equals(t.getFilterId()))
                        .findFirst().get()));

        //Добавляем новые фильтры
        feedFilters.stream().filter(t -> "0".equals(t.getFilterId()))
                .forEach(this::addFilter);
        waitForElement(getFilterBlock().getWrappedElement(), 10, not(WebElementMatchers.isDisplayed()));
    }

    protected abstract EditFilterBlockBase getFilterBlock();

    protected void editFilter(FilterItem filterItem, FeedFilterBase feedFilter) {
        filterItem.clickEditButton();
        getFilterBlock().setConfig(config);
        fillFilterParameters(feedFilter);
    }

    protected void addFilter(FeedFilterBase feedFilter) {
        clickAddFilter();
        getFilterBlock().setConfig(config);
        fillFilterParameters(feedFilter);
    }

    private void fillFilterParameters(FeedFilterBase feedFilter) {
        if (feedFilter instanceof PerformanceFeedFilter) {
            ((EditPerformanceFilterBlock) getFilterBlock()).fillParameters((PerformanceFeedFilter) feedFilter);
        } else {
            ((EditDynamicFilterBlock) getFilterBlock()).fillParameters((DynamicFeedFilter) feedFilter);
        }
    }

    protected List<? extends FeedFilterBase> getFeedFilters(List<? extends FeedFilterBase> expectedBeans) {
        Map<String, FeedFilterBase> expectedFiltersMap = expectedBeans.stream()
                .collect(Collectors.toMap(x -> x.getFilterId(), x -> x));
        Set<String> keys = expectedFiltersMap.keySet().stream().collect(Collectors.toSet());
        List<? extends FeedFilterBase> result = filterItems.stream()
                .filter(t ->
                        (expectedFiltersMap.containsKey(t.getFilterId())
                                && (keys.remove(t.getFilterId()) || true)))
                .map(t -> getFilter(t, expectedFiltersMap.get(t.getFilterId())))
                .collect(toList());
        if (!keys.isEmpty()) {
            takeScreenshot();
            throw new DirectWebError("Не найдены фильтры: ".join(",", keys));
        }
        return result;
    }

    private FeedFilterBase getFilter(FilterItem block, FeedFilterBase expectedBean) {
        block.clickEditButton();
        FeedFilterBase actualFilter = expectedBean instanceof PerformanceFeedFilter ?
                ((EditPerformanceFilterBlock) getFilterBlock())
                        .getFormFieldsAccording((PerformanceFeedFilter) expectedBean)
                : ((EditDynamicFilterBlock) getFilterBlock()).getFormFieldsAccording((DynamicFeedFilter) expectedBean);
        getFilterBlock().clickCancelButton();
        return actualFilter;
    }
}
