package cz.moneta.test.dsl.hypos.tasks;

import cz.moneta.test.dsl.Harness;
import cz.moneta.test.dsl.hypos.dataPrepare.RealtyData;
import cz.moneta.test.dsl.hypos.dataPrepare.valuations.FlatValuationData;
import cz.moneta.test.dsl.hypos.dataPrepare.valuations.HouseValuationData;
import cz.moneta.test.dsl.hypos.enums.RealtySearchType;
import cz.moneta.test.dsl.hypos.pages.cadaster.CadasterRedocDetailPage;
import cz.moneta.test.dsl.hypos.pages.contract.ContractHistoryPage;
import cz.moneta.test.dsl.hypos.pages.contract.realty.CreateNewUnitPage;
import cz.moneta.test.dsl.hypos.pages.contract.realty.OrderValuationPage;
import cz.moneta.test.dsl.hypos.pages.contract.realty.UnitDetailPage;
import cz.moneta.test.dsl.hypos.pages.contract.realty.ValuationDetailPage;
import cz.moneta.test.dsl.hypos.pages.realty.RealtyMenuPage;
import cz.moneta.test.dsl.util.DateUtils;
import cz.moneta.test.dsl.util.data.YamlLoader;

import java.util.function.Function;

import static cz.moneta.test.dsl.hypos.enums.HyposLogType.TASK;
import static cz.moneta.test.dsl.hypos.tasks.HyposTasks.defaultDateFormat;

public class ValuationTasks {
    private final String YAML_REALTY_DETAIL_PATH = "yamls/hypos/realtyDetails";

    private final Harness harness;

    private HyposCommonTasks tasks;

    public ValuationTasks(Harness harness) {
        this.harness = harness;
        this.tasks = harness.tasks().hypos().hyposCommonTasks();
    }

    /**
     * Create new realty in predefined contract.
     *
     * @param realtyType - String defining if realty will be flat, house or land.
     * @return
     */
    public Function<ContractHistoryPage, UnitDetailPage> setNewRealty(int realtyType) {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        YamlLoader yamlLoader = new YamlLoader(YAML_REALTY_DETAIL_PATH, RealtyData.class);
        RealtyData data = yamlLoader.parseObject();

        return start -> start
                .clickRealty()
                .clickSearchRealty()
                .selectRealtyType(data.realtyCategories.get(realtyType).realtyCategory)
                .fillAreaName(data.realtyCategories.get(realtyType).propertyArea)
                .clickAutosuggestLink(data.realtyCategories.get(realtyType).propertyArea)
                .fillDescriptiveNumber(data.realtyCategories.get(realtyType).documentNumber)
                .clickSearchButton()
                .clickCreateNewUnit()
                .selectRealtyType(data.realtyCategories.get(realtyType).finalType)
                .selectPledgeType(data.realtyCategories.get(realtyType).pledgeType)
                .selectPledgeCode(data.realtyCategories.get(realtyType).pledgeCode)
                .clickUseThisUnitCheckbox()
                .clickSaveButton();
    }

    /**
     * Checker, if unit is used in other realty, if so, it is removed to it could be used elsewhere.
     *
     * @param realtyType - Int defining if realy will be flat, house or land.
     * @return
     */
    public Function<UnitDetailPage, UnitDetailPage> checkUnitUsage(int realtyType) {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        YamlLoader yamlLoader = new YamlLoader(YAML_REALTY_DETAIL_PATH, RealtyData.class);
        RealtyData data = yamlLoader.parseObject();
        return start -> start
                .clickAddUnit()
                .selectUnitCategory(data.realtyCategories.get(realtyType).realtyCategory)
                .fillCadastralTerritory(data.realtyCategories.get(realtyType).propertyArea)
                .clickAutosuggestLink(data.realtyCategories.get(realtyType).propertyArea)
                .fillDocumentNumber(data.realtyCategories.get(realtyType).documentNumber)
                .clickSubmit()
                .checkUnitUsage(data.realtyCategories.get(realtyType).orientationNumber, data.realtyCategories.get(realtyType).tdPosition)
                .clickRealty()
                .clickRealtyDetail();
    }

    /**
     * Adding unit to realty. Method checkUnitUsage should be called before this, because if unit is used elsewhere and it isn't removed first, method fail.
     *
     * @param realtyType - Int defining if realy will be flat, house or land.
     * @return
     */
    public Function<UnitDetailPage, UnitDetailPage> addUnitToRealty(int realtyType) {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        YamlLoader yamlLoader = new YamlLoader(YAML_REALTY_DETAIL_PATH, RealtyData.class);
        RealtyData data = yamlLoader.parseObject();

        return start -> start
                .clickAddUnit()
                .selectUnitCategory(data.realtyCategories.get(realtyType).realtyCategory)
                .fillCadastralTerritory(data.realtyCategories.get(realtyType).propertyArea)
                .clickAutosuggestLink(data.realtyCategories.get(realtyType).propertyArea)
                .fillDocumentNumber(data.realtyCategories.get(realtyType).documentNumber)
                .clickSubmit()
                .addUnit(data.realtyCategories.get(realtyType).orientationNumber);
    }

    /**
     * Go to Market valuation form
     *
     * @return
     */
    public Function<ContractHistoryPage, OrderValuationPage> goToMarketValuationForm() {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        return start -> start
                .clickRealty()
                .clickRealtyDetail()
                .clickOnOrderValuation();
    }

    /**
     * Check if all elements that should be visible in specific sections are visible.
     *
     * @return
     */
    public Function<OrderValuationPage, OrderValuationPage> checkElementsInOrderForm() {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        return start -> start
                .checkSharedElements()
                .checkFlatElements()
                .checkHouseElements()
                .checkLandElements();
    }

    public Function<OrderValuationPage, ValuationDetailPage> doFlatMarketValuation() {
        return doFlatMarketValuation(1);
    }

    public Function<OrderValuationPage, ValuationDetailPage> doHouseMarketValuation() {
        return doHouseMarketValuation(0);
    }

    /**
     * Create a new valuation for realty type - Flat.
     *
     * @param valuationType - Int defining if realty will go on Verification, desktop, full or online process.
     * @return
     */
    public Function<OrderValuationPage, ValuationDetailPage> doFlatMarketValuation(int valuationType) {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        YamlLoader yamlLoader = new YamlLoader("yamls/hypos/valuations/flatValuations", FlatValuationData.class);
        FlatValuationData data = yamlLoader.parseObject();

        return start -> start.selectOrdererType("Mortgage")
                .selectFinalType(data.finalType)
                .selectPurpose(data.valuationDetails.get(valuationType).purpose)
                .insertAddressStreet(data.addressStreet)
                .insertAddressDescriptiveNumber(data.addressNumber)
                .insertAddressTown(data.addressTown)
                .insertAddressPostCode(data.addressPostCode)
                .selectContactRole("Žadatel o úvěr")
                .insertPurchasePrice(data.valuationDetails.get(valuationType).price)
                .clickDocumentsAvailable()
                .selectDisposition(data.valuationDetails.get(valuationType).disposition)
                .insertArea(data.valuationDetails.get(valuationType).area)
                .selectFlatState(data.valuationDetails.get(valuationType).state)
                .selectFlatLocation(data.valuationDetails.get(valuationType).placing)
                .insertTotalAreaOther(data.valuationDetails.get(valuationType).areaOther)
                .clickPropertyNotRentedFlat()
                .insertOutsideParking(data.valuationDetails.get(valuationType).outsideParking)
                .insertInsideParking(data.valuationDetails.get(valuationType).insideParking)
                .insertGarage(data.valuationDetails.get(valuationType).garage)
                .selectConstructionMaterialFlat(data.valuationDetails.get(valuationType).houseType)
                .selectTechnicalStateFlat(data.valuationDetails.get(valuationType).houseStatus)
                .insertBuildYearFlat(data.valuationDetails.get(valuationType).houseYear)
                .insertFloors(data.valuationDetails.get(valuationType).houseFloors)
                .clickElevatorYes()
                .clickDocumentsLater()
                .clickSave()
                .waitForValuationComplete();
    }

    /**
     * Create a new valuation for realty type - House.
     *
     * @param valuationType - Int defining if realy will go on Verification, desktop, full or online process.
     * @return
     */
    public Function<OrderValuationPage, ValuationDetailPage> doHouseMarketValuation(int valuationType) {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        YamlLoader yamlLoader = new YamlLoader("yamls/hypos/valuations/houseValuations", HouseValuationData.class);
        HouseValuationData data = yamlLoader.parseObject();
        return start -> start
                .selectFinalType(data.finalType)
                .selectPurpose(data.valuationDetails.get(valuationType).purpose)
                .insertAddressStreet(data.addressStreet)
                .insertAddressDescriptiveNumber(data.addressNumber)
                .insertAddressTown(data.addressTown)
                .insertAddressPostCode(data.addressPostCode)
                .selectContactRole("Žadatel o úvěr")
                .insertPurchasePrice(data.valuationDetails.get(valuationType).price)
                .clickDocumentsAvailable()
                .selectConstructionMaterial(data.valuationDetails.get(valuationType).material)
                .insertBuildYear(data.valuationDetails.get(valuationType).year)
                .insertAreaTotalHouse(data.valuationDetails.get(valuationType).area)
                .insertFloorAreaHouse(data.valuationDetails.get(valuationType).areaOther)
                .selectTechnicalState(data.valuationDetails.get(valuationType).state)
                .clickPropertyNotRentedHouse()
                .clickGarageInHouse()
                .clickNoSeparateGarageInHouse()
                .clickDocumentsLater()
                .clickSave()
                .waitForValuationComplete();
    }

    /**
     * Tests if order is set to defer state with correct comment.
     *
     * @return
     */
    public Function<ValuationDetailPage, ValuationDetailPage> deferOrder() {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        return start -> start
                .clickDeferOrder()
                .insertDelayUntil("31.12.2023")
                .insertDelayComment(ValuationDetailPage.autoComment)
                .clickDeferOrderInput()
                .acceptAlert()
                .verifyLastOperation("odloženo")
                .verifyLastOperationComment();
    }

    /**
     * Tests if order is set to cancel state with correct comment.
     *
     * @return
     */
    public Function<ValuationDetailPage, ValuationDetailPage> cancelOrder() {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        return start -> start
                .clickCancelOrder()
                .insertCancelComment(ValuationDetailPage.autoComment)
                .clickCancelOrderInput()
                .acceptAlert()
                .verifyLastOperation("zrušeno")
                .verifyLastOperationComment();
    }

    /**
     * Tests if order is gived  with correct comment.
     *
     * @return
     */
    public Function<ValuationDetailPage, ValuationDetailPage> giveOrder() {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        return start -> start
                .clickGiveOrder()
                .insertForwardComment(ValuationDetailPage.autoComment)
                .clickGiveOrderInput()
                .acceptAlert()
                .verifyLastOperation("předáno")
                .verifyLastOperationComment();
    }

    /**
     * Tests if order is taken.
     *
     * @return
     */
    public Function<ValuationDetailPage, ValuationDetailPage> takeOrder() {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        return start -> start
                .clickTakeOrder()
                .acceptAlert()
                .verifyLastOperation("převzato");
    }

    /**
     * Fill required fields in valuation form for finished the order.
     *
     * @return
     */
    public Function<ValuationDetailPage, ValuationDetailPage> finishOrder() {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        return start -> start
                .clickTakeOrder()
                .acceptAlert()
                .verifyLastOperation("převzato")
                .clickRisks()
                .setAllRisksNo()
                .clickFinalSection()
                .insertReproductivePrice(500000)
                .insertCurrentPrice(1000000)
                .clickSaveAll()
                .clickProcessOrder()
                .acceptAlert()
                .waitForValuationCompleted();
    }

    public Function<ValuationDetailPage, ValuationDetailPage> finishFlatOrder() {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        return start -> start.clickTakeOrder()
                .acceptAlert()
                .verifyLastOperation("převzato")
                .clickRealtyDescription()
                .selectFlatHeating("Centrální dálkové (Kotel mimo stavbu)")
                .selectFlatHeatingMedium("Plyn")
                .clickFlatAircondition()
                .insertBuildApart("8")
                .clickBuildGas()
                .clickBuildSolarPower()
                .clickRisks()
                .setAllRisksNo()
                .clickFinalSection()
                .clickComparativeMethod()
                .clickComparatorAddRealty()
                .insertComparatorRealtyArea("50")
                .insertComparatorPrice("50000")
                .clickComparatorAddRealty()
                .insertComparatorRealtyArea("50")
                .insertComparatorPrice("50000")
                .clickComparatorAddRealty()
                .insertComparatorRealtyArea("50")
                .insertComparatorPrice("50000")
                .insertReproductivePrice(7000000)
                .insertCurrentPrice(6800000)
                .clickSaveAll()
                .clickProcessOrder()
                .acceptAlert()
                .waitForValuationCompleted();
    }

    public Function<ValuationDetailPage, ValuationDetailPage> finishBuildingOrder() {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        return start -> start.clickTakeOrder()
                .acceptAlert()
                .verifyLastOperation("převzato")
                .clickRealtyDescription()
                .selectHouseMainBuildType("Samostatně stojící")
                .selectHouseReconstruction("Bez rekonstrukce")
                .selectHouseHeatingSystem("Centrální domovní (Kotel ve stavbě)")
                .selectHouseHeatingMedium("Plyn")
                .clickHouseWaterNetwork()
                .clickHouseSewerageNetwork()
                .clickHouseSewerageNetworkOwn()
                .clickHouseGasNetwork()
                .clickHouseSolarPower()
                .clickHouseAircondition()
                .clickHouseFloorDownstair()
                .clickHouseFloorUpstair()
                .clickHouseFloorAttic()
                .insertBuiltUpArea("80")
                .insertFloorArea("140")
                .clickRisks()
                .setAllRisksNo()
                .clickFinalSection()
                .clickComparativeMethod()
                .clickComparatorAddRealty()
                .insertComparatorRealtyArea("50")
                .insertSurroundSpace("800")
                .insertComparatorLandArea("80")
                .insertComparatorPrice("50000")
                .clickComparatorAddRealty()
                .insertComparatorRealtyArea("50")
                .insertComparatorLandArea("80")
                .insertComparatorPrice("50000")
                .clickComparatorAddRealty()
                .insertComparatorRealtyArea("50")
                .insertComparatorLandArea("80")
                .insertComparatorPrice("50000")
                .insertCurrentPrice(6800000)
                .insertLocalInvestigationDate(DateUtils.getFormattedTodayDate(defaultDateFormat))
                .clickSaveAll()
                .clickProcessOrder()
                .acceptAlert()
                .waitForValuationCompleted();
    }

    /**
     * Checking presence of elements that should be located in valuation form.
     * @return
     */
    public Function<ValuationDetailPage, ValuationDetailPage> checkFlatElements() {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        String[] selectElements = {"flat-technical-description", "flat-unit-placement", "flat-unit-type", "flat-unit-disposition", "flat-technical-status",
                "flat-heating", "flat-technical-condition-before-reconstruction", "flat-building-type", "flat-building-technical-condition", "flat-building-land",
                "flat-building-realty-locality", "flat-building-traffic-car"};

        String[] inputElement = {"flat-building-flat-floor", "flat-floor-area", "flat-countable-floor-area", "flat-floor-area-other", "flat-terrace-area",
                "flat-balcony-loggia-area", "flat-lumber-area", "flat-front-garden-area", "flat-cellar-area", "flat-reconstruction-year", "flat-wear",
                "flat-indoor-parking", "flat-outdoor-parking", "flat-garage", "flat-building-construction-year", "flat-building-reconstruction-year", "flat-building-wear", "flat-building-upstairs-floor", "flat-acceptable-budget"};

        String[] textAreaElements = {"flat-garage-note", "flat-reconstruction-description", "flat-budget-comment"};

        return start -> start
                .clickRealtyDescription()
                .checkElements(selectElements, "select")
                .checkElements(inputElement, "input")
                .checkElements(textAreaElements, "textarea")
                .clickRealtyDescription();
    }

    /**
     * Verifying correctness of reproductive price formula.
     * @return
     */
    public Function<ValuationDetailPage, ValuationDetailPage> verifyReproductivePrice() {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        return start -> start
                .clickRealtyDescription()
                .clickFinalSection()
                .doCalculationAndVerify();
    }

    public Function<RealtyMenuPage, CadasterRedocDetailPage> searchCadasterRedocDetail(String areaCode, String lv) {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        return start -> start.clickRealtySearchPage()
                .selectRealtyType(RealtySearchType.PAPER_OF_OWNERSHIP.getValue())
                .fillAreaCode(areaCode)
                .clickAutosuggestLink(areaCode)
                .fillLv(lv)
                .clickSearchButton()
                .clickRedocDetail(lv);
    }

    public Function<ContractHistoryPage, CreateNewUnitPage> createNewFlatUnit(String areaCode, String flatNumber) {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        return start -> start.clickRealty()
                .clickSearchRealty()
                .selectRealtyType(RealtySearchType.FLAT.getValue())
                .fillAreaCode(areaCode)
                .clickAutosuggestLink(areaCode)
                .fillFlatNumber(flatNumber)
                .clickSearchButton()
                .clickCreateNewSearchUnit()
                .selectRealtyType("Jednotka")
                .selectPledgeType("Nemovitosti - bydlení")
                .clickSavePledgeButton();
    }

    public Function<ContractHistoryPage, CreateNewUnitPage> createNewBuildingUnit(String areaCode, String buildingNumber) {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        return start -> start.clickRealty()
                .clickSearchRealty()
                .selectRealtyType(RealtySearchType.HOUSE.getValue())
                .fillAreaCode(areaCode)
                .clickAutosuggestLink(areaCode)
                .fillDescriptiveNumber(buildingNumber)
                .clickSearchButton()
                .clickCreateNewSearchUnit()
                .selectRealtyType("Budova")
                .selectPledgeType("Nemovitosti - bydlení")
                .selectPledgeCode("33 - Rodinný dům s pozemkem")
                .clickSavePledgeButton();
    }

    public Function<ContractHistoryPage, UnitDetailPage> addLandToUnit(String lv, String areaCode, String buildingNumber, String landNumber) {
        tasks.hyposLog(TASK, new Object(){}.getClass().getEnclosingMethod().getName());
        return start -> start.clickRealty()
                .clickRealtyDetail(buildingNumber)
                .clickAddUnit()
                .selectUnitCategory(RealtySearchType.LAND.getValue())
                .fillCadastralTerritory(areaCode)
                .clickAutosuggestLink(areaCode)
                .fillDocumentNumber(lv)
                .fillLandNumber(landNumber)
                .clickSubmit()
                .addUnit(landNumber);
    }
}