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

import cz.moneta.test.dsl.hypos.components.Menu;
import cz.moneta.test.dsl.hypos.pages.HyposPageFlow;
import cz.moneta.test.harness.endpoints.hypos.HyposEndpoint;
import cz.moneta.test.harness.support.web.*;
import org.junit.Assert;
import org.openqa.selenium.WebElement;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public interface OrderValuationPage extends HyposPageFlow<OrderValuationPage>, Menu {
    String A_BACKTOREALTYDETAIL = "//a[contains(text(), 'návrat na detail celku')]";
    String SELECT_ORDERER_TYPE = "//select[@id='orderer-type']";
    String SELECT_FINALTYPE = "//select[@id = 'realty-type']";
    String SELECT_REALTYUNITTYPE = "//select[@id = 'realty-unit-type']";
    String SELECT_REALTYBUILDINGTYPE = "//select[@id = 'realty-building-type']";
    String SELECT_PURPOSE = "//select[@id = 'ucel']";
    String INPUT_ADDRESSSTREET = "//input[@name = 'address_street']";
    String INPUT_ADDRESSTOWN = "//input[@name = 'address_town']";
    String INPUT_ADDRESSTOWNPART = "//input[@name = 'address_town_part']";
    String INPUT_ADDRESSDESCRIPTIVENUMBER = "//input[@name = 'address_descriptive_number']";
    String INPUT_ADDRESSPOSTCODE = "//input[@name = 'address_post_code']";
    String SELECT_CONTACTROLE = "//select[@id = 'kontaktRole']";
    String INPUT_PURCHASEPRICE = "//tr[@id='segment-purchase-price' and not(@class='hidden')]//input[@id='kupniCena']";
    String INPUT_SHARE = "//input[@id = 'kupniPodil']";
    String COMBOBOX_DOCUMENTSAVAILABLE_YES = "//input[@name = 'documents_available' and @value = '1']";
    String COMBOBOX_DOCUMENTSAVAILABLE_NO = "//input[@name = 'documents_available' and @value = '0']";
    String CHECKBOX_COMPLETEDVALUATION = "//input[@id = 'podkladyVypracovaneOceneni']";
    String TH_FLATDESCRIBE = "//th[text() = 'popis bytu']";
    String TH_BUILDINGDESCRIBE = "//th[text() = 'popis budovy']";

    //FLAT when documents available = yes
    String SELECT_DISPOSITION = "//select[@id = 'bytDispozicniReseni']";
    String INPUT_FLATAREA = "//input[@id = 'bytPlochaBezPrislusenstvi']";
    String SELECT_FLATSTATE = "//select[@id = 'bytStavBytu']";
    String INPUT_FLATLOCATION = "//select[@id = 'bytUmisteniJednotky']";
    String INPUT_TOTALAREAOTHER = "//input[@id = 'bytPlochaPrislusenstvi']";
    String COMBOBOX_PROPERTYRENTED_YES_FLAT = "//input[@name = 'realty[flat][rented]' and @value = '1']";
    String COMBOBOX_PROPERTYRENTED_NO_FLAT = "//input[@name = 'realty[flat][rented]' and @value = '0']";
    String INPUT_OUTSIDEPARKING = "//input[@id = 'bytPocetParkovacichMistVenkovni']";
    String INPUT_INSIDEPARKING = "//input[@id = 'bytPocetParkovacichMistVnitrni']";
    String INPUT_GARAGE = "//input[@id = 'bytPocetParkovacichMistStani']";
    String SELECT_CONSTRUCTIONMATERIAL_FLAT = "//select[@name = 'realty[flat_building][flat_building_type]']";
    String INPUT_BUILDYEAR_FLAT = "//input[@id = 'bytovyDumRokVystavby']";
    String COMBOBOX_ELEVATOR_YES = "//input[@name = 'realty[flat_building][elevator]' and @value = '1']";
    String COMBOBOX_ELEVATOR_NO = "//input[@name = 'realty[flat_building][elevator]' and @value = '0']";
    String SELECT_TECHNICALSTATE_FLAT = "//select[@id = 'bytovyDumTechnickyStav']";
    String INPUT_FLOORS = "//input[@id = 'bytovyDumPocetNadzemnichPodlazi']";

    //HOUSE
    String SELECT_CONSTRUCTIONMATERIAL_HOUSE = "//select[@id = 'construction-material-house']";
    String INPUT_BUILDYEAR_HOUSE = "//input[@id = 'budovaRokVystavby']";
    String INPUT_AREATOTAL_HOUSE = "//input[@id = 'budovaSoucetPlochPozemku']";
    String COMBOBOX_GARAGEINHOUSE_YES = "//input[@name = 'realty[house][garage_in_house]' and @value = '1']";
    String COMBOBOX_GARAGEINHOUSE_NO = "//input[@name = 'realty[house][garage_in_house]' and @value = '0']";
    String SELECT_TECHNICALSTATE_HOUSE = "//select[@name = 'realty[house][technical_condition_house]']";
    String COMBOBOX_PROPERTYRENTED_YES_HOUSE = "//input[@name = 'realty[house][rented]' and @value = '1']";
    String COMBOBOX_PROPERTYRENTED_NO_HOUSE = "//input[@name = 'realty[house][rented]' and @value = '0']";
    String INPUT_FLOOREAREA_HOUSE = "//input[@id = 'budovaZapocitatelnaPodlahovaPlocha']";
    String COMBOBOX_SEPARATEGARAGE_YES_HOUSE = "//input[@name = 'realty[house][garage_separate]' and @value = '1']";
    String COMBOBOX_SEPARATEGARAGE_NO_HOUSE = "//input[@name = 'realty[house][garage_separate]' and @value = '0']";
    String INPUT_PURPOSEDETAIL = "//textarea[@id = 'detailUcelu']";

    //when documents available = no
    String H4_WARNINGMESSAGE = "//h4[@id = 'error-msg-duration-increase']";
    String COMBOBOX_OWNERCOOPERATE_YES = "//input[@name = 'documents_owner_cooperate' and @value = '1']";
    String COMBOBOX_OWNERCOOPERATE_NO = "//input[@name = 'documents_owner_cooperate' and @value = '0']";
    String COMBOBOX_HASDOCUMENTS_YES = "//input[@name = 'documents_owner_has_documents' and @value = '1']";
    String COMBOBOX_HASDOCUMENTS_NO = "//input[@name = 'documents_owner_has_documents' and @value = '0']";
    String COMBOBOX_ATYPICAL_YES = "//input[@name = 'documents_atypical_property' and @value = '1']";
    String COMBOBOX_ATYPICAL_NO = "//input[@name = 'documents_atypical_property' and @value = '0']";

    String INPUT_ATTACHMENT = "//input[@id = 'attachment']";
    String BUTTON_ANOTHERATTACHMENT = "//button[text() = 'další příloha']";
    String COMBOBOX_DOCUMENTSLATER_YES = "//input[@name = 'documents_later' and @value = '1']";
    String COMBOBOX_DOCUMENTSLATER_NO = "//input[@name = 'documents_later' and @value = '0']";
    String INPUT_ADDITIONALINFO = "//textarea[@id = 'informaceProOdhadce']";
    String INPUT_SAVE = "//input[@id = 'submit-appraisement-order']";

    String A_ORDERDETAIL = "//*[text() = 'Detail objednávky']";

    HashMap<String, Boolean> purposeTp = new HashMap<String, Boolean>() {{
        put("americká hypotéka", true);
        put("další zajištění", true);
        put("konsolidace", true);
        put("koupě", true);
        put("refinancování - dokončená nemovitost", true);
        put("refinancování - následná rekonstrukce", true);
        put("refinancování - rozestavěno", false);
        put("rekonstrukce", true);
        put("úprava rozsahu celku", true);
        put("vypořádání SJM / dědictví", true);
        put("výstavba", false);
        put("změna zástavy", true);
        put("ostatní", true);
    }};

    String[] elementsWithoutDocuments = {
            H4_WARNINGMESSAGE, COMBOBOX_OWNERCOOPERATE_YES, COMBOBOX_OWNERCOOPERATE_NO, COMBOBOX_HASDOCUMENTS_YES, COMBOBOX_HASDOCUMENTS_NO,
            COMBOBOX_ATYPICAL_YES, COMBOBOX_ATYPICAL_NO};

    /**
     * Checking elements that are similar for all types of realty.
     *
     * @return
     */
    @CustomAction
    default OrderValuationPage checkSharedElements() {
        HyposEndpoint endpoint = getEndpoint(HyposEndpoint.class);

        String[] sharedElements = {SELECT_FINALTYPE, SELECT_REALTYUNITTYPE, SELECT_PURPOSE, INPUT_ADDRESSSTREET, INPUT_ADDRESSTOWN,
                INPUT_ADDRESSTOWN, INPUT_ADDRESSTOWNPART, INPUT_ADDRESSDESCRIPTIVENUMBER, INPUT_ADDRESSPOSTCODE, SELECT_CONTACTROLE,
                INPUT_PURCHASEPRICE, INPUT_SHARE, CHECKBOX_COMPLETEDVALUATION, INPUT_ATTACHMENT, BUTTON_ANOTHERATTACHMENT,
                INPUT_ADDITIONALINFO, INPUT_SAVE};

        for (String sharedElement : sharedElements) {
            endpoint.waitForElementsToLoad(5, sharedElement);
        }
        log("All shared elements are present.");
        return null;
    }

    /**
     * Checking elements for Flats realty. Method iterates over two lists - RealtyTypes and purposeTypes for final realty type Flat.
     * In iterations, there are 2 checkers for what elements should be visible for every combination of those lists.
     * If both of them are true, the elements check for additional section is made.
     * If at least one of the condition is false, check for additional section not visible is made.
     *
     * @return
     */
    @CustomAction
    default OrderValuationPage checkFlatElements() {
        HyposEndpoint endpoint = getEndpoint(HyposEndpoint.class);
        selectFinalType("Jednotka");

        HashMap<String, Boolean> realtyTypes = new HashMap<String, Boolean>() {{
            put("Bytová jednotka", true);
            put("Ateliér", true);
            put("Loft", true);
            put("Mezonet", true);
            put("Penthouse", true);
            put("Jiné", false);
        }};

        String[] elementsWithDocumentsFlats = {SELECT_DISPOSITION, INPUT_FLATAREA, SELECT_FLATSTATE, INPUT_FLATLOCATION, INPUT_TOTALAREAOTHER,
                COMBOBOX_PROPERTYRENTED_YES_FLAT, COMBOBOX_PROPERTYRENTED_NO_FLAT, INPUT_OUTSIDEPARKING, INPUT_INSIDEPARKING, INPUT_INSIDEPARKING,
                SELECT_CONSTRUCTIONMATERIAL_FLAT, INPUT_BUILDYEAR_FLAT, COMBOBOX_ELEVATOR_YES, COMBOBOX_ELEVATOR_NO, SELECT_TECHNICALSTATE_FLAT,
                INPUT_FLOORS};

        for (Map.Entry<String, Boolean> realtyType : realtyTypes.entrySet()) {
            selectRealtyFlatType(realtyType.getKey());

            Boolean additionalSectionProperty = realtyType.getValue();

            for (Map.Entry<String, Boolean> purposeType : purposeTp.entrySet()) {
                selectPurpose(purposeType.getKey());

                Boolean additionalSectionPurpose = purposeType.getValue();

                if (additionalSectionProperty && additionalSectionPurpose) {
                    clickDocumentsAvailable();
                    Arrays.stream(elementsWithDocumentsFlats).forEach(e -> endpoint.waitForElementsToLoad(5, e));

                    clickDocumentsNotAvailable();
                    Arrays.stream(elementsWithoutDocuments).forEach(e -> endpoint.waitForElementsToLoad(5, e));
                } else {
                    String errorMessage = String.format("Section for flat describe is visible in %s with purpose %s.", realtyType, purposeType);
                    Assert.assertFalse(errorMessage, endpoint.isElementVisible(1, TH_FLATDESCRIBE, Lookup.XPATH));
                }
            }

        }
        log("All elements for flats are present.");
        return null;
    }

    /**
     * Checking elements for Houses realty. Method iterates over two lists - RealtyTypes and purposeTypes for final realty type Building.
     * In iterations, there are 2 checkers for what elements should be visible for every combination of those lists.
     * If both of them are true, the elements check for additional section is made.
     * If at least one of the condition is false, check for additional section not visible is made.
     *
     * @return
     */
    @CustomAction
    default OrderValuationPage checkHouseElements() {
        HyposEndpoint endpoint = getEndpoint(HyposEndpoint.class);
        selectFinalType("Budova");

        HashMap<String, Boolean> realtyTypes = new HashMap<String, Boolean>() {{
            put("Rodinný dům", true);
            put("Rekreační objekt", false);
            put("Jiná - rezidenční", false);
            put("Jiná - nerezidenční", false);
        }};

        String[] elementsWithDocumentsHouses = {SELECT_CONSTRUCTIONMATERIAL_HOUSE, INPUT_BUILDYEAR_HOUSE, INPUT_AREATOTAL_HOUSE, COMBOBOX_GARAGEINHOUSE_YES,
                COMBOBOX_GARAGEINHOUSE_NO, SELECT_TECHNICALSTATE_HOUSE, COMBOBOX_PROPERTYRENTED_YES_HOUSE, COMBOBOX_PROPERTYRENTED_NO_HOUSE, INPUT_FLOOREAREA_HOUSE,
                COMBOBOX_SEPARATEGARAGE_YES_HOUSE, COMBOBOX_SEPARATEGARAGE_NO_HOUSE};

        for (Map.Entry<String, Boolean> realtyType : realtyTypes.entrySet()) {
            selectRealtyHouseType(realtyType.getKey());
            Boolean additionalSectionProperty = realtyType.getValue();

            for (Map.Entry<String, Boolean> purposeType : purposeTp.entrySet()) {
                selectPurpose(purposeType.getKey());
                Boolean additionalSectionPurpose = purposeType.getValue();

                if (additionalSectionProperty && additionalSectionPurpose) {
                    clickDocumentsAvailable();
                    Arrays.stream(elementsWithDocumentsHouses).forEach(e -> endpoint.waitForElementsToLoad(5, e));

                    clickDocumentsNotAvailable();
                    Arrays.stream(elementsWithoutDocuments).forEach(e -> endpoint.waitForElementsToLoad(5, e));
                } else {
                    String errorMessage = String.format("Section for building describe is visible in %s with purpose %s.", realtyType, purposeType);
                    Assert.assertFalse(errorMessage, endpoint.isElementVisible(1, TH_BUILDINGDESCRIBE, Lookup.XPATH));
                }
            }
        }
        log("All elements for houses are present.");
        return null;
    }

    /**
     * Check elements for land realty. This method iterates only in one list - PurposeTypes.
     * In this iteration, there is only check, that no additional section is visible and if purpose is "ostatní" that one specific element is showed.
     *
     * @return
     */
    @CustomAction
    default OrderValuationPage checkLandElements() {
        HyposEndpoint endpoint = getEndpoint(HyposEndpoint.class);
        selectFinalType("Pozemek");

        for (Map.Entry<String, Boolean> purposeType : purposeTp.entrySet()) {
            selectPurpose(purposeType.getKey());
            System.out.println(purposeType.getKey());
            Assert.assertFalse("Combobox for documents availability is visible.", endpoint.isElementVisible(1, COMBOBOX_DOCUMENTSAVAILABLE_YES, Lookup.XPATH));
            Assert.assertFalse("Combobox for documents availability is visible.", endpoint.isElementVisible(1, COMBOBOX_DOCUMENTSAVAILABLE_NO, Lookup.XPATH));

            if (purposeType.getKey().equals("ostatní")) {
                Assert.assertTrue(endpoint.isElementVisible(INPUT_PURPOSEDETAIL));
                Assert.assertFalse("Combobox for documents availability is visible.", endpoint.isElementVisible(1, COMBOBOX_DOCUMENTSAVAILABLE_YES, Lookup.XPATH));
                Assert.assertFalse("Combobox for documents availability is visible.", endpoint.isElementVisible(1, COMBOBOX_DOCUMENTSAVAILABLE_NO, Lookup.XPATH));
            }
        }
        return null;
    }

    @Click(A_BACKTOREALTYDETAIL)
    OrderValuationPage clickBackToRealtyDetail();

    @Select(value = SELECT_ORDERER_TYPE, andWait = @Wait(value = LOADER, until = Until.GONE))
    OrderValuationPage selectOrdererType(String ordereType);

    @Select(value = SELECT_FINALTYPE, andWait = @Wait(value = LOADER, until = Until.GONE))
    OrderValuationPage selectFinalType(String finalType);

    @Select(SELECT_REALTYUNITTYPE)
    OrderValuationPage selectRealtyFlatType(String realtyType);

    @Select(SELECT_REALTYBUILDINGTYPE)
    OrderValuationPage selectRealtyHouseType(String realtyType);

    @Select(value = SELECT_PURPOSE, andWait = @Wait(value = LOADER, until = Until.GONE))
    OrderValuationPage selectPurpose(String purpose);

    @TypeInto(INPUT_ADDRESSSTREET)
    OrderValuationPage insertAddressStreet(String street);

    @TypeInto(INPUT_ADDRESSTOWN)
    OrderValuationPage insertAddressTown(String town);

    @TypeInto(INPUT_ADDRESSTOWNPART)
    OrderValuationPage insertAddressTownPart(String townPart);

    @TypeInto(INPUT_ADDRESSDESCRIPTIVENUMBER)
    OrderValuationPage insertAddressDescriptiveNumber(String descriptiveNumber);

    @TypeInto(INPUT_ADDRESSPOSTCODE)
    OrderValuationPage insertAddressPostCode(String postCode);

    @TypeInto(SELECT_CONTACTROLE)
    @KeyPress(Key.ENTER)
    OrderValuationPage selectContactRole(String contactRole);

    @TypeInto(INPUT_SHARE)
    OrderValuationPage insertShare(int share);

    @Click(value = COMBOBOX_DOCUMENTSAVAILABLE_YES, andWait = @Wait(value = LOADER, until = Until.GONE))
    OrderValuationPage clickDocumentsAvailable();

    @Click(COMBOBOX_DOCUMENTSAVAILABLE_NO)
    OrderValuationPage clickDocumentsNotAvailable();

    @Click(CHECKBOX_COMPLETEDVALUATION)
    OrderValuationPage clickCompletedValuation();

    @TypeInto(SELECT_DISPOSITION)
    @KeyPress(Key.ENTER)
    OrderValuationPage selectDisposition(String disposition);

    @TypeInto(INPUT_FLATAREA)
    OrderValuationPage insertArea(int area);

    @TypeInto(SELECT_FLATSTATE)
    @KeyPress(Key.ENTER)
    OrderValuationPage selectFlatState(String flatState);

    @TypeInto(INPUT_FLATLOCATION)
    @KeyPress(Key.ENTER)
    OrderValuationPage selectFlatLocation(String flatLocation);

    @TypeInto(INPUT_TOTALAREAOTHER)
    OrderValuationPage insertTotalAreaOther(int totalAreaOther);

    @Click(COMBOBOX_PROPERTYRENTED_YES_FLAT)
    OrderValuationPage clickPropertyRentedFlat();

    @Click(value = COMBOBOX_PROPERTYRENTED_NO_FLAT, andWait = @Wait(value = LOADER, until = Until.GONE))
    OrderValuationPage clickPropertyNotRentedFlat();

    @TypeInto(INPUT_OUTSIDEPARKING)
    OrderValuationPage insertOutsideParking(int outsideParking);

    @TypeInto(INPUT_INSIDEPARKING)
    OrderValuationPage insertInsideParking(int insideParking);

    @TypeInto(INPUT_GARAGE)
    OrderValuationPage insertGarage(int garage);

    @TypeInto(SELECT_CONSTRUCTIONMATERIAL_FLAT)
    @KeyPress(Key.ENTER)
    OrderValuationPage selectConstructionMaterialFlat(String constructionMaterial);

    @TypeInto(INPUT_BUILDYEAR_FLAT)
    OrderValuationPage insertBuildYearFlat(String buildYear);

    @Click(COMBOBOX_ELEVATOR_YES)
    OrderValuationPage clickElevatorYes();

    @Click(COMBOBOX_ELEVATOR_NO)
    OrderValuationPage clickElevatorNo();

    @TypeInto(SELECT_TECHNICALSTATE_FLAT)
    @KeyPress(Key.ENTER)
    OrderValuationPage selectTechnicalStateFlat(String technicalState);

    @TypeInto(INPUT_FLOORS)
    OrderValuationPage insertFloors(int floors);

    @TypeInto(SELECT_CONSTRUCTIONMATERIAL_HOUSE)
    @KeyPress(Key.ENTER)
    OrderValuationPage selectConstructionMaterial(String constructionMaterial);

    @TypeInto(INPUT_BUILDYEAR_HOUSE)
    OrderValuationPage insertBuildYear(int buildYear);

    @TypeInto(INPUT_AREATOTAL_HOUSE)
    OrderValuationPage insertAreaTotalHouse(int areaTotal);

    @Click(COMBOBOX_GARAGEINHOUSE_YES)
    OrderValuationPage clickGarageInHouse();

    @Click(COMBOBOX_GARAGEINHOUSE_NO)
    OrderValuationPage clickNoGarageInHouse();

    @TypeInto(SELECT_TECHNICALSTATE_HOUSE)
    @KeyPress(Key.ENTER)
    OrderValuationPage selectTechnicalState(String technicalState);

    @Click(COMBOBOX_PROPERTYRENTED_YES_HOUSE)
    OrderValuationPage clickPropertyRentedHouse();

    @Click(value = COMBOBOX_PROPERTYRENTED_NO_HOUSE, andWait = @Wait(value = LOADER, until = Until.GONE))
    OrderValuationPage clickPropertyNotRentedHouse();

    @TypeInto(INPUT_FLOOREAREA_HOUSE)
    OrderValuationPage insertFloorAreaHouse(int areaOther);

    @Click(COMBOBOX_SEPARATEGARAGE_YES_HOUSE)
    OrderValuationPage clickSeparateGarageInHouse();

    @Click(COMBOBOX_SEPARATEGARAGE_NO_HOUSE)
    OrderValuationPage clickNoSeparateGarageInHouse();

    @CheckElementPresent(H4_WARNINGMESSAGE)
    OrderValuationPage checkWarningMessage();

    @Click(COMBOBOX_OWNERCOOPERATE_YES)
    OrderValuationPage clickOwnerCooperate();

    @Click(COMBOBOX_OWNERCOOPERATE_NO)
    OrderValuationPage clickOwnerNotCooperate();

    @Click(COMBOBOX_HASDOCUMENTS_YES)
    OrderValuationPage clickHasDocuments();

    @Click(COMBOBOX_HASDOCUMENTS_NO)
    OrderValuationPage clickHasNoDocuments();

    @Click(COMBOBOX_ATYPICAL_YES)
    OrderValuationPage clickIsAtypical();

    @Click(COMBOBOX_ATYPICAL_NO)
    OrderValuationPage clickIsNotAtypical();

    @Click(INPUT_ATTACHMENT)
    OrderValuationPage clickAttachment();

    @Click(BUTTON_ANOTHERATTACHMENT)
    OrderValuationPage clickAnotherAttachment();

    @Click(COMBOBOX_DOCUMENTSLATER_YES)
    OrderValuationPage clickDocumentsLater();

    @Click(COMBOBOX_DOCUMENTSLATER_NO)
    OrderValuationPage clickDocumentsNotLater();

    @TypeInto(INPUT_ADDITIONALINFO)
    OrderValuationPage insertAdditionalInfo(String additionalInfo);

    @Click(INPUT_SAVE)
    OrderValuationPage clickSave();

    @Wait(value = A_ORDERDETAIL, waitSecondsForElement = 180)
    @Click(A_ORDERDETAIL)
    ValuationDetailPage waitForValuationComplete();

    @CustomAction
    default OrderValuationPage insertPurchasePrice(int purchasePrice) {
        HyposEndpoint endpoint = getEndpoint(HyposEndpoint.class);
        List<WebElement> elements = endpoint.findAndGetListOfElements(INPUT_PURCHASEPRICE, Lookup.XPATH);
        if (!elements.isEmpty()) {
            endpoint.type(() -> INPUT_PURCHASEPRICE, Integer.toString(purchasePrice), false, Lookup.XPATH);
        }
        return null;
    }
}
