package cz.moneta.test.dsl.kasanova;

import cz.moneta.test.dsl.Harness;
import cz.moneta.test.dsl.kasanova.authentication.KSNLoginPage;
import cz.moneta.test.dsl.kasanova.components.enums.*;
import cz.moneta.test.dsl.util.DateUtils;
import cz.moneta.test.harness.context.StoreAccessor;
import cz.moneta.test.harness.endpoints.kasanova.KasanovaEndpoint;
import cz.moneta.test.harness.support.auth.Credentials;
import cz.moneta.test.harness.support.web.Click;
import cz.moneta.test.harness.support.web.CustomAction;
import cz.moneta.test.harness.support.web.Key;
import cz.moneta.test.harness.support.web.KeyPress;
import cz.moneta.test.harness.support.web.Lookup;
import cz.moneta.test.harness.support.web.Select;
import cz.moneta.test.harness.support.web.SwitchToDefaultContent;
import cz.moneta.test.harness.support.web.TypeInto;
import cz.moneta.test.harness.support.web.Until;
import cz.moneta.test.harness.support.web.Wait;
import org.junit.jupiter.api.Assertions;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static cz.moneta.test.dsl.kasanova.components.KSNMainMenu.ROOT_MENU;

public interface KSNUtils<A> extends KSNCommonElements, StoreAccessor, KSNStorno<A> {

    @CustomAction
    default A coinSplitTable(KSNCoinSplits coinSplit, String text) {
        String xpath = String.format(COINSPLIT_DYNAMIC_PATH, coinSplit.getValue());
        KasanovaEndpoint endpoint = getEndpoint(KasanovaEndpoint.class);
        endpoint.type(() -> xpath, text, false, Lookup.XPATH);
        return null;
    }

    @CustomAction
    default A checkRedirect(String redirectFunctionTitle) {
        String FUNCTION_TITLE = "//div[@class='cTitle']";
        KasanovaEndpoint endpoint = getEndpoint(KasanovaEndpoint.class);
        endpoint.waitForElementsToLoad(20, Lookup.XPATH, FUNCTION_TITLE);
        String title = endpoint.getText(FUNCTION_TITLE, Lookup.XPATH);
        Assertions.assertEquals(redirectFunctionTitle, title);
        return null;
    }

    @CustomAction
    default A checkFunctionIsDone() {
        final String INPUT_REPORT = "//div[@id='reportPanel']//input[@id='report']";
        KasanovaEndpoint endpoint = getEndpoint(KasanovaEndpoint.class);
        endpoint.waitForElementsToLoad(30, Lookup.XPATH, Until.PRESENT_IN_DOM, ROOT_MENU);
        endpoint.switchToDefaultContent();
        endpoint.switchToFrame("links");
        endpoint.isElementPresent(INPUT_REPORT, Lookup.XPATH);
        String reportMessage;
        boolean checkReportMessage = false;
        for (int i = 0; i < 60; i++) {
            reportMessage = endpoint.getAttribute(INPUT_REPORT, Lookup.XPATH, "value");
            checkReportMessage = reportMessage.startsWith("Funkce byla úspěšně odeslána a akceptována Host Tellerem.");
            if (checkReportMessage) {
                break;
            } else {
                endpoint.sleep(TimeUnit.MILLISECONDS, 500);
            }
        }
        Assertions.assertTrue(checkReportMessage);
        return null;
    }

    @CustomAction
    default KSNLoginPage logOut() {
        String ROOT_MENU = "//div[@id='root_menu']";
        String MENU_09_BUTTON = "//button[text()='Údržbové operace']";
        String MENU_09_SUBMENU_02_BUTTON = "//td[text()='Údržbové operace']//ancestor::tbody//button[text()='Dočasné odhlášení']";
        KasanovaEndpoint endpoint = getEndpoint(KasanovaEndpoint.class);
        endpoint.switchToDefaultContent();
        endpoint.switchToFrame(MAIN_IFRAME_NAME);
        endpoint.waitForElementsToLoad(40, Lookup.XPATH, ROOT_MENU);
        endpoint.waitForElementsToLoad(20, Lookup.XPATH, MENU_09_BUTTON);
        endpoint.click(() -> MENU_09_BUTTON, Lookup.XPATH);
        endpoint.click(() -> MENU_09_SUBMENU_02_BUTTON, Lookup.XPATH);
        endpoint.waitForElementsToLoad(30, Kasanova.CONTINUE_BUTTON);
        return null;
    }

    @CustomAction
    default A fillIdentificationAndSymbolsMini() {
        KasanovaEndpoint endpoint = getEndpoint(KasanovaEndpoint.class);
        endpoint.type(() -> IDENTIFICATION_ADDRESS_INPUT, KSNAdress.getRandomAdressValue(), false);
        if (endpoint.isElementVisible(1, DESCRIPTION_INPUT, Lookup.DEFAULT)) {
            endpoint.type(() -> DESCRIPTION_INPUT, KSNDescriptions.getRandomDescriptionValue(), false);
        }
        endpoint.type(() -> VARIABLE_SYMBOL_INPUT, KSNNumberGenerator.getRandomNumberValue(), false);
        endpoint.type(() -> CONSTANT_SYMBOL_INPUT, KSNNumberGenerator.getRandomNumberValue(), false);
        endpoint.type(() -> SPECIFIC_SYMBOL_INPUT, KSNNumberGenerator.getRandomNumberValue(), false);
        return null;
    }

    @CustomAction
    default A fillIdentificationAndSymbolsShort() {
        KasanovaEndpoint endpoint = getEndpoint(KasanovaEndpoint.class);
        endpoint.type(() -> IDENTIFICATION_CLIENT_NAME_INPUT, KSNNames.getRandomNameValue(), true);
        endpoint.type(() -> IDENTIFICATION_PERSONAL_NUMBER_INPUT, DateUtils.getRandomDate(1940, 2000, KSNPatterns.DD_MM_YYYY.getValue()), false);
        endpoint.selectByVisibleText(IDENTIFICATION_SEX_SELECT, KSNGender.getRandomGenderValue());
        endpoint.selectByVisibleText(IDENTIFICATION_PERSONAL_NUMBER_TYPE_SELECT, KSNIdCards.getRandomIdCardValue());
        endpoint.type(() -> IDENTIFICATION_ID_NUMBER_INPUT, KSNNumberGenerator.getRandomNumberValue(), false);
        if (endpoint.isElementVisible(1, IDENTIFICATION_NATIONALITY_SELECT, Lookup.DEFAULT)) {
            endpoint.selectByVisibleText(IDENTIFICATION_NATIONALITY_SELECT, KSNCountries.getRandomCountryValue());
        }
        endpoint.type(() -> IDENTIFICATION_ADDRESS_INPUT, KSNAdress.getRandomAdressValue(), false);
        if (endpoint.isElementVisible(1, DESCRIPTION_INPUT, Lookup.DEFAULT)) {
            endpoint.type(() -> DESCRIPTION_INPUT, KSNDescriptions.getRandomDescriptionValue(), false);
        }
        endpoint.type(() -> VARIABLE_SYMBOL_INPUT, KSNNumberGenerator.getRandomNumberValue(), false);
        endpoint.type(() -> CONSTANT_SYMBOL_INPUT, KSNNumberGenerator.getRandomNumberValue(), false);
        endpoint.type(() -> SPECIFIC_SYMBOL_INPUT, KSNNumberGenerator.getRandomNumberValue(), false);
        return null;
    }

    @CustomAction
    default A fillIdentificationAndSymbolsLong() {
        KasanovaEndpoint endpoint = getEndpoint(KasanovaEndpoint.class);
        endpoint.type(() -> IDENTIFICATION_CLIENT_NAME_INPUT, KSNNames.getRandomNameValue(), true);
        endpoint.type(() -> IDENTIFICATION_PERSONAL_NUMBER_INPUT, DateUtils.getRandomDate(1940, 2000, KSNPatterns.DD_MM_YYYY.getValue()), false);
        endpoint.selectByVisibleText(IDENTIFICATION_SEX_SELECT, KSNGender.getRandomGenderValue());
        endpoint.selectByVisibleText(IDENTIFICATION_PERSONAL_NUMBER_TYPE_SELECT, KSNIdCards.getRandomIdCardValue());
        endpoint.type(() -> IDENTIFICATION_ID_NUMBER_INPUT, KSNNumberGenerator.getRandomNumberValue(), false);
        endpoint.type(() -> IDENTIFICATION_ID_END_DATE_INPUT, DateUtils.getRandomDate(YEAR_ONE.getYear(), YEAR_MORE.getYear(), KSNPatterns.DDMMYYYY.getValue()), true);
        String coutry = KSNCountries.getRandomCountryValue();
        endpoint.selectByVisibleText(IDENTIFICATION_COUNTRY_ID_SELECT, coutry);
        endpoint.selectByVisibleText(IDENTIFICATION_LONG_TERM_RESIDENCE_SELECT, coutry);
        endpoint.selectByVisibleText(IDENTIFICATION_NATIONALITY_SELECT, coutry);
        endpoint.type(() -> IDENTIFICATION_BIRTH_PLACE_INPUT, KSNBirthPlaces.getRandomBirthPlaceValue(), true);
        endpoint.type(() -> IDENTIFICATION_ADDRESS_INPUT, KSNAdress.getRandomAdressValue(), true);
        if (endpoint.isElementVisible(1, DESCRIPTION_INPUT, Lookup.DEFAULT)) {
            endpoint.type(() -> DESCRIPTION_INPUT, KSNDescriptions.getRandomDescriptionValue(), false);
        }
        endpoint.type(() -> VARIABLE_SYMBOL_INPUT, KSNNumberGenerator.getRandomNumberValue(), false);
        endpoint.type(() -> CONSTANT_SYMBOL_INPUT, KSNNumberGenerator.getRandomNumberValue(), false);
        endpoint.type(() -> SPECIFIC_SYMBOL_INPUT, KSNNumberGenerator.getRandomNumberValue(), false);
        return null;
    }

    @CustomAction
    default A fillIdentificationAndSymbolsForDepositbook() {
        KasanovaEndpoint endpoint = getEndpoint(KasanovaEndpoint.class);
        endpoint.selectByVisibleText(IDENTIFICATION_PERSONAL_NUMBER_TYPE_SELECT, KSNIdCards.getRandomIdCardValue());
        endpoint.type(() -> IDENTIFICATION_ID_NUMBER_INPUT, KSNNumberGenerator.getRandomNumberValue(), false);
        endpoint.type(() -> IDENTIFICATION_ADDRESS_INPUT, KSNAdress.getRandomAdressValue(), false);
        endpoint.type(() -> DESCRIPTION_INPUT, KSNDescriptions.getRandomDescriptionValue(), false);
        endpoint.type(() -> VARIABLE_SYMBOL_INPUT, KSNNumberGenerator.getRandomNumberValue(), false);
        endpoint.type(() -> CONSTANT_SYMBOL_INPUT, KSNNumberGenerator.getRandomNumberValue(), false);
        endpoint.type(() -> SPECIFIC_SYMBOL_INPUT, KSNNumberGenerator.getRandomNumberValue(), false);
        return null;
    }

    @CustomAction
    default A fillDepositBookBalance(String depositBookBalanceInput) {
        KasanovaEndpoint endpoint = getEndpoint(KasanovaEndpoint.class);
        String depositbookBalanceICBS = endpoint.getAttribute(DEPOSITBOOK_BALANCE_ICBS, Lookup.XPATH, "value");
        endpoint.type(() -> depositBookBalanceInput, depositbookBalanceICBS, false);
        return null;
    }

    @Wait(explicitWaitSeconds = 3)
    @CustomAction
    default A dismissPrintWindow() {
        // KasanovaEndpoint endpoint = getEndpoint(KasanovaEndpoint.class);

        // TODO: workerounded by browser argument --kiosk-printing and explicitWait
        // endpoint.dismissEdgePrintDialog();
        // if(endpoint.isHeadlessModeOn() == false)
        //   endpoint.switchToFrame(MAIN_FRAME);

        return null;
    }

    // Fee coinsplit table is filled with nominals according to field 'Poplatek'
    @CustomAction
    default A fillFeeCoinsplit() {
        final String INPUT_FEE = "//input[@name='fee2']"; // Poplatek
        KasanovaEndpoint endpoint = getEndpoint(KasanovaEndpoint.class);
        String feeValue = endpoint.getAttribute(INPUT_FEE, Lookup.XPATH, "value");
        int feeValueInt = 0;
        try {
            NumberFormat formatter = NumberFormat.getNumberInstance(Locale.GERMAN);
            feeValueInt = formatter.parse(feeValue).intValue();
        } catch(ParseException e) {
            log("Parsing of fee [" + feeValue + "] failed. Continue with 0");
        }
        List<Integer> tableValues = new ArrayList<>(Arrays.asList(new Integer[] {5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1}));
        Map<String, String> coinSplitMap = new LinkedHashMap<>();

        for (int value : tableValues) {
            if (feeValueInt <= 0) {
                break;
            }
            int result = feeValueInt / value;
            if (result > 0) {
                if (value >= 100) {
                    coinSplitMap.put("csFee2Main-CZK-B-" + value, String.valueOf(result));
                } else {
                    coinSplitMap.put("csFee2Main-CZK-C-" + value, String.valueOf(result));
                }
                feeValueInt = feeValueInt % value;
            }
        }
        for (String item : coinSplitMap.keySet()) {
            String xpath = String.format(COINSPLIT_DYNAMIC_PATH, item);
            endpoint.type(() -> xpath, coinSplitMap.get(item), false, Lookup.XPATH);
        }
        return null;
    }

    @CustomAction
    default A doVerification(Harness harness, String verifyAmount, String verifyAccount, Credentials verifyBanker) {
        String VERIFY_BANKER_UID = "kasanova-config.verify-banker.uid";
        KasanovaEndpoint endpoint = getEndpoint(KasanovaEndpoint.class);
        endpoint.waitForElementsToLoad(80, Until.GONE, LOADER_DIV);
        endpoint.waitForAnyElementToLoad(30, Lookup.XPATH, BUTTON_KASADIALOG, VERIFY_DIALOG_IFRAME);
        endpoint.switchToFrame(VERIFY_DIALOG_IFRAME, Lookup.XPATH);
        endpoint.waitForElementsToLoad(30, Lookup.XPATH, Until.VISIBLE, VERIFY_DIALOG_AMOUNT);
        endpoint.type(() -> VERIFY_DIALOG_AMOUNT, verifyAmount, false, Lookup.XPATH);
        endpoint.type(() -> VERIFY_DIALOG_ACCOUNT, verifyAccount, false, Lookup.XPATH);
        endpoint.type(() -> VERIFY_DIALOG_UID, harness.getConfig(VERIFY_BANKER_UID), false, Lookup.XPATH);
        endpoint.type(() -> VERIFY_DIALOG_SSOID, verifyBanker.getUsername(), false, Lookup.XPATH);
        endpoint.type(() -> VERIFY_DIALOG_PASSWORD, verifyBanker.getPassword(), false, Lookup.XPATH);
        endpoint.switchToDefaultContent();
        endpoint.switchToFrame(MAIN_IFRAME_NAME);
        endpoint.click(() -> VERIFY_BUTTON, Lookup.XPATH);
        return null;
    }

    @CustomAction
    default A kasanovaDialogClickOK() {
        KasanovaEndpoint endpoint = getEndpoint(KasanovaEndpoint.class);
        if (endpoint.isElementVisible(20, BUTTON_KASADIALOG, Lookup.XPATH)) {
            endpoint.click(() -> BUTTON_KASADIALOG_OK, Lookup.XPATH);
        }
        return null;
    }

    @CustomAction
    default A kasanovaDialogClickYes() {
        KasanovaEndpoint endpoint = getEndpoint(KasanovaEndpoint.class);
        if (endpoint.isElementVisible(20, BUTTON_KASADIALOG, Lookup.XPATH)) {
            endpoint.click(() -> BUTTON_KASADIALOG_YES, Lookup.XPATH);
        }
        return null;
    }

    @Click(BUTTON_BACK2)
    A backToMainMenu();

    @SwitchToDefaultContent
    A switchToDefaultFrame();

    @TypeInto(DEPOSIT_AMOUNT_INPUT)
    @KeyPress(Key.TAB)
    A depositAmount(String text);

    @TypeInto(WITHDRAW_AMOUNT_INPUT)
    @KeyPress(Key.TAB)
    A withdrawAmount(String text);

    @TypeInto(SMENA_AMOUNT_INPUT)
    @KeyPress(Key.TAB)
    A smenaAmount(String text);

    @TypeInto(VYPLATA_AMOUNT_INPUT)
    @KeyPress(Key.TAB)
    A vyplataAmount(String text);

    @TypeInto(DEBET_AMOUNT_INPUT)
    A debetAmount(String text);

    @TypeInto(DEBET_AMOUNT_INPUT2)
    A debetAmount2(String text);

    @Select(value = IDENTIFICATION_AUTH_PERSON, by = Lookup.XPATH)
    A authPerson(String text);

    @Click(value = IDENTIFICATION_AUTH_PERSON_1, by = Lookup.XPATH)
    A authPerson1();

    @Click(value = IDENTIFICATION_AUTH_PERSON_3, by = Lookup.XPATH)
    A authPerson3();

    @Click(value = IDENTIFICATION_AUTH_PERSON_4, by = Lookup.XPATH)
    A authPerson4();

    @Select(ORIGINE_PURPOSE_SELECT)
    A originePurpose(String text);

    @Select(ORIGINE_PURPOSE2_SELECT)
    A originePurpose2(String text);

    @Select(RELATION_TO_THE_OWNER_SELECT)
    A relationToTheOwner(String text);

    @Click(value = PAGE_TITLE, by = Lookup.XPATH)
    @Click(BUTTON_PRINT)
    A continueWithPrintAction();

    @Wait(value = BUTTON_SAVE_TMP, until = Until.CLICKABLE, waitSecondsForElement = 20)
    @Click(BUTTON_SAVE_TMP)
    A continueWithSaveAction();

    @Click(BUTTON_CESSION)
    A clickCession();

    @Click(BUTTON_PRINT_INFO)
    A clickPrintInfo();

    @TypeInto(DEPOSITBOOK_LINE_NUMBER)
    A lineNumber(String text);

    @Select(IDENTIFICATION_SEX_SELECT)
    A sex(String text);

}
