package cz.moneta.test.dsl.hypos.pages.contract.approval;

import cz.moneta.test.dsl.hypos.components.Menu;
import cz.moneta.test.dsl.hypos.pages.HyposPageFlow;
import cz.moneta.test.dsl.util.data.hypos.ScoringParameter;
import cz.moneta.test.harness.context.StoreAccessor;
import cz.moneta.test.harness.endpoints.hypos.HyposEndpoint;
import cz.moneta.test.harness.support.web.CustomAction;
import cz.moneta.test.harness.support.web.Lookup;
import cz.moneta.test.harness.support.web.Wait;
import cz.moneta.test.harness.support.util.Level;
import org.openqa.selenium.WebElement;
import java.util.ArrayList;
import java.util.List;

import static cz.moneta.test.dsl.hypos.enums.ScoringParameterType.*;
import static cz.moneta.test.dsl.hypos.pages.contract.approval.ScoringDetailPage.RESPONSE_INPUT_TAB;

@Wait(RESPONSE_INPUT_TAB)
public interface ScoringDetailPage extends HyposPageFlow<ScoringDetailPage>, StoreAccessor, Menu {
    String RESPONSE_INPUT_TAB = "//a[contains(text(),'Žádost - výstupy')]";
    String RESPONSE_INPUT_DIV = "//div[@id='tabs-response']";
    String REFUSAL_REASON_TABLE = RESPONSE_INPUT_DIV + "//th[text()='Důvody zamítnutí']/ancestor::table[1]//tbody/tr";
    String LIMIT_VALUE = RESPONSE_INPUT_DIV + "//th[text()='%1$s']/ancestor::table[1]//td[text()='%2$s']/following-sibling::td[2]";
    String BONITY_VALUE = RESPONSE_INPUT_DIV + "//th[text()='%1$s']/ancestor::table[1]//td[text()='%2$s']/..//td[text()='%3$s']/preceding-sibling::td[3]";
    String BONITY_LTV_VALUE = RESPONSE_INPUT_DIV + "//th[text()='%1$s']/ancestor::table[1]//td[text()='%2$s']/following-sibling::td[3]";
    String APPROVAL_RESULT_VALUE = RESPONSE_INPUT_DIV + "//table//th[text()='%s']/following-sibling::td";
    String REFUSAL_REASON_VALUES = REFUSAL_REASON_TABLE + "/td[1]";
    String REFUSAL_REASON_VALUE = REFUSAL_REASON_TABLE + "[%s]/td[1]";

    String RESPONSE_APPROVAL_TAB = "//a[contains(text(),'r.č')]";
    String STRATEGY_VALUE = "//div[@id='approval-response']//th[text()='%1$s']/ancestor::table[1]//td[text()='%2$s']/following-sibling::td[2]";

    @CustomAction
    default ScoringDetailPage checkScoringParametersLimit(List<ScoringParameter> scoringParameters) {
        HyposEndpoint endpoint = getEndpoint(HyposEndpoint.class);
        endpoint.click(() -> RESPONSE_INPUT_TAB);
        scoringParameters.stream()
                .filter(type -> type.getType().equals(LIMIT))
                .forEach(scoringParameter -> {
                    String parameterXpath = String.format(LIMIT_VALUE, scoringParameter.getType().getValue(), scoringParameter.getName());
                    endpoint.waitForElementsToLoad(5,parameterXpath);
                    String parameterValue = endpoint.getText(parameterXpath);
                    log(Level.INFO,(scoringParameter.getExpectedValue().equals(parameterValue) ? "OK " : "ERROR ") +
                            LIMIT.getValue() + ", " + scoringParameter.getName() + " - expected: " +
                            scoringParameter.getExpectedValue() + " found: " + parameterValue);
                });
        return null;
    }

    @CustomAction
    default ScoringDetailPage checkScoringParametersBonity(List<ScoringParameter> scoringParameters) {
        HyposEndpoint endpoint = getEndpoint(HyposEndpoint.class);
        endpoint.click(() -> RESPONSE_INPUT_TAB);
        scoringParameters.stream()
                .filter(type -> type.getType().equals(BONITY))
                .forEach(scoringParameter -> {
                    String parameterXpath = String.format(BONITY_VALUE, scoringParameter.getType().getValue(), scoringParameter.getName(), scoringParameter.getAutomat().getValue());
                    endpoint.waitForElementsToLoad(5,parameterXpath);
                    String parameterValue = endpoint.getText(parameterXpath);
                    log(Level.INFO,(scoringParameter.getExpectedValue().equals(parameterValue) ? "OK " : "ERROR ") +
                            BONITY.getValue() + ", " + scoringParameter.getName() + " " +
                            scoringParameter.getAutomat().getValue() + " - expected: " +
                            scoringParameter.getExpectedValue() + " found: " + parameterValue);
                });
        return null;
    }

    @CustomAction
    default ScoringDetailPage checkScoringParametersBonityLtv(List<ScoringParameter> scoringParameters) {
        HyposEndpoint endpoint = getEndpoint(HyposEndpoint.class);
        endpoint.click(() -> RESPONSE_INPUT_TAB);
        scoringParameters.stream()
                .filter(type -> type.getType().equals(BONITY_LTV))
                .forEach(scoringParameter -> {
                    String parameterXpath = String.format(BONITY_LTV_VALUE, scoringParameter.getType().getValue(), scoringParameter.getName());
                    endpoint.waitForElementsToLoad(5,parameterXpath);
                    String parameterValue = endpoint.getText(parameterXpath);
                    log(Level.INFO,(scoringParameter.getExpectedValue().equals(parameterValue) ? "OK " : "ERROR ") +
                            BONITY_LTV.getValue() + ", " + scoringParameter.getName() + " - expected: " +
                            scoringParameter.getExpectedValue() + " found: " + parameterValue);
                });
        return null;
    }

    @CustomAction
    default ScoringDetailPage checkScoringParametersStrategy(List<ScoringParameter> scoringParameters) {
        HyposEndpoint endpoint = getEndpoint(HyposEndpoint.class);
        endpoint.click(() -> RESPONSE_APPROVAL_TAB);
        scoringParameters.stream()
                .filter(type -> type.getType().equals(STRATEGY))
                .forEach(scoringParameter -> {
                    String parameterXpath = String.format(STRATEGY_VALUE, scoringParameter.getType().getValue(), scoringParameter.getName());
                    endpoint.waitForElementsToLoad(5,parameterXpath);
                    String parameterValue = endpoint.getText(parameterXpath);
                    log(Level.INFO,(scoringParameter.getExpectedValue().equals(parameterValue) ? "OK " : "ERROR ") +
                            STRATEGY.getValue() + ", " + scoringParameter.getName() + " - expected: " +
                            scoringParameter.getExpectedValue() + " found: " + parameterValue);
                });
        return null;
    }

    @CustomAction
    default ScoringDetailPage checkScoringParameterApprovalResult(List<ScoringParameter> scoringParameters) {
        HyposEndpoint endpoint = getEndpoint(HyposEndpoint.class);
        endpoint.click(() -> RESPONSE_INPUT_TAB);
        ScoringParameter scoringParameter = scoringParameters.stream()
                .filter(type -> type.getType().equals(APPROVAL_RESULT))
                .findFirst()
                .orElseThrow(() -> new IllegalStateException("No scoring parameter with type APPROVAL_RESULT found"));
        String parameterXpath = String.format(APPROVAL_RESULT_VALUE, scoringParameter.getType().getValue());
        endpoint.waitForElementsToLoad(5,parameterXpath);
        String parameterValue = endpoint.getText(parameterXpath);
        log(Level.INFO,(scoringParameter.getExpectedValue().equals(parameterValue) ? "OK " : "ERROR ") +
                APPROVAL_RESULT.getValue() + " - expected: " + scoringParameter.getExpectedValue() + " found: " + parameterValue
        );
        return null;
    }

    @CustomAction
    default ScoringDetailPage checkScoringParametersRefusalReason(List<ScoringParameter> scoringParameters) {
        HyposEndpoint endpoint = getEndpoint(HyposEndpoint.class);
        endpoint.click(() -> RESPONSE_INPUT_TAB);
        endpoint.waitForElementsToLoad(5,REFUSAL_REASON_VALUES);
        List<WebElement> resultRefusalElements = endpoint.findAndGetListOfElements(REFUSAL_REASON_VALUES, Lookup.XPATH);
        List<String> resultRefusalValues = new ArrayList<>();
        for (int i = 1; i <= resultRefusalElements.size(); i++) {
            String xpath = String.format(REFUSAL_REASON_VALUE, i+1);
            resultRefusalValues.add(endpoint.getText(xpath));
        }
        scoringParameters.stream()
                .filter(parameterType -> parameterType.getType().equals(REFUSAL_REASON))
                .forEach(parameter -> {
                    int indexOfParameter = resultRefusalValues.indexOf(parameter.getName());
                    if (indexOfParameter != -1) {
                        log(Level.INFO,"OK " + REFUSAL_REASON.getValue() + ", " + parameter.getName());
                        resultRefusalValues.remove(indexOfParameter);
                    } else {
                        log(Level.INFO,"ERROR " + REFUSAL_REASON.getValue() + ", " + parameter.getName() + " - Parameter not find");
                    }
                });
        resultRefusalValues
                .forEach(parameter -> log(Level.INFO,"ERROR " + REFUSAL_REASON.getValue() + ", " + parameter + " - Parameter missing in input" ));
        return null;
    }
}