const monitoringRoute = {
    polyline: null
};

let lastPositionCapture = null;
let auxLastPositionCapture = null;

function capturePosition({lat, lng}) {
    const config = Session.get("cityConfig");

    if (Array.isArray(Session.get("tripDriver")))
        return setMonitoring(false);

    if (Array.isArray(config)) return;

    if (config.enableTripRecalculation == false) return;

    if (!isMonitoring()) return;

    if (!verifyTripExistDistanceAndTime()) return;

    const pathRoute = getPathRouteTraveled();

    const lastPosition = getLastPositionByPath(pathRoute);

    if (lastPosition != null) {
        if (
            plugin.google.maps.geometry.spherical.computeDistanceBetween(
                lastPosition,
                {lat, lng}
            ) < 50
        ) {
            return updateInfoMonitoring();
        }
    }

    if (!verifyPositionCaptureCurrent({lat, lng}))
        return;

    pathRoute.push({lat, lng});

    saveRouteTraveled(pathRoute);

    updateInfoMonitoring();
}

function verifyPositionCaptureCurrent({lat, lng}) {
    if (lastPositionCapture == null) {
        lastPositionCapture = {lat, lng};
        return false;
    }

    if (plugin.google.maps.geometry.spherical.computeDistanceBetween({lat, lng}, lastPositionCapture) > 200) {
        if (auxLastPositionCapture != null) {
            if (plugin.google.maps.geometry.spherical.computeDistanceBetween(auxLastPositionCapture, lastPositionCapture) > 1000) {
                auxLastPositionCapture = lastPositionCapture;
                return false;
            }
            auxLastPositionCapture = null;
        } else {
            auxLastPositionCapture = {lat, lng};
            return false;
        }
    }

    lastPositionCapture = {lat, lng};

    return true;
}

function verifyTripExistDistanceAndTime() {
    const trip = Session.get("tripDriver");

    if (trip.distance == null)
        return false;

    if (trip.estimatedTripTime == null)
        return false;

    return true;
}

function getLastPositionByPath(path) {
    return path[path.length - 1] || null;
}

function saveRouteTraveled(path) {
    verifyRecalculateIsTripCurrent();

    Session.set(
        "routeTraveled",
        plugin.google.maps.geometry.encoding.encodePath(path));
}

function getPathRouteTraveled() {
    const routeTraveled = Session.get("routeTraveled");
    if (Array.isArray(routeTraveled)) return routeTraveled;

    return plugin.google.maps.geometry.encoding.decodePath(routeTraveled);
}

function isMonitoring() {
    const status = Session.get("statusMonitoring");

    if (!Array.isArray(Session.get("tripDriver"))) {
        const {status} = Session.get("tripDriver");

        if (status !== STATUS_IN_PROGRESS)
            return false;
    }


    if (Array.isArray(status)) return false;

    return status;
}

function setMonitoring(status) {
    const config = Session.get("cityConfig");

    if (!status) {
        lastPositionCapture = null;
        auxLastPositionCapture = null;
        Session.delete("dateTimeInProgress");
        Session.delete("routeTraveled");
        viewController.elementProperty.removeClass(
            ".container-km-time-trip",
            "active"
        );

        return;
    }

    if (config.enableTripRecalculation == false) return;

    if (!verifyTripExistDistanceAndTime()) return;

    if (Array.isArray(Session.get("dateTimeInProgress")))
        Session.set("dateTimeInProgress", new Date());

    showInfoMonitoring();

    Session.set("statusMonitoring", status);
}

function showInfoMonitoring() {
    viewController.elementProperty.addClass(".container-km-time-trip", "active");
    updateInfoMonitoring();
}

function verifyRecalculateIsTripCurrent() {
    const trip = Session.get("tripDriver");

    if (!Array.isArray(Session.get("lastTripRecalculate"))) {
        if (trip.tripReference !== Session.get("lastTripRecalculate")) {
            Session.delete("routeTraveled");
            Session.set("dateTimeInProgress", new Date());
            Session.set("lastTripRecalculate", trip.tripReference)
        }
    } else {
        Session.set("lastTripRecalculate", trip.tripReference)
    }
}

function updateInfoMonitoring() {
    if (!verifyTripExistDistanceAndTime()) return;

    const trip = Session.get("tripDriver");

    verifyRecalculateIsTripCurrent();

    viewController.elementProperty.getElement(
        ".container-km-time-trip",
        element => {
            element.innerHTML = `<div>
                <span>${getTextTranslate("trip", "text-hired")}:</span>
                <span>${trip.distance}km/${trip.estimatedTripTime}min</span>
            </div>
            <div>
                <span>${getTextTranslate("trip", "text-rotated")}:</span>
                <span>${getKmRouteTraveled().toFixed(3)}km/${parseInt(
                getMinutesRouteTraveled()
            )}min</span>
            </div>`;
        }
    );
}

function verifyRecalculateFare() {
    try {
        const config = Session.get("cityConfig");
        const trip = Session.get("tripDriver");

        const km = getKmRouteTraveled();
        const minute = getMinutesRouteTraveled();

        const valueMarginForRecalculation = parseFloat(config.marginForRecalculation);
        const tripDistance = parseFloat(trip.distance);

        const estimatedTime = trip.estimatedTripTime;

        const willBeRecalculatedOrNot = () => {
                if(config.enableTripRecalculation){
                    return (km > parseFloat(config.recalculationFromKm)
                    || ((tripDistance - valueMarginForRecalculation) < km && km < (tripDistance + valueMarginForRecalculation))
                    || minute !== estimatedTime)
                }
        };

        if (!willBeRecalculatedOrNot())
            return null;

        const newPrice = calculateNewPrice(km, minute);

        if (ConfigGeneral().get("enable_floating_price_recalculation") != null)
            if (ConfigGeneral().get("enable_floating_price_recalculation") == false) {
                if (parseFloat(trip.price) < newPrice) return {price: newPrice, km, minute};
            } else {
                return {price: newPrice, km, minute};
            }

        return null;
    } catch (e) {
        return null;
    }
}

function getMinutesRouteTraveled() {
    if(Array.isArray(Session.get("dateTimeInProgress")))
        return 0;
    const start = new Date(Session.get("dateTimeInProgress"));

    const end = new Date();

    return parseInt((end - start) / 60 / 1000);
}

function getKmRouteTraveled() {
    let meters = 0;
    const path = getPathRouteTraveled();

    path.map((point, index) => {
        if (index === 0) return;

        meters += plugin.google.maps.geometry.spherical.computeDistanceBetween(
            path[index - 1],
            point
        );
    });

    return meters / 1000;
}

function calculateNewPrice(km, minute, isTaximeter = false) {
    if (Array.isArray(Session.get("tripDriver")))
        return 0;

    const {fare, tripWayPoints, distance, price, multiplierDynamic,tripDiscountCoupon} = Session.get("tripDriver");

    if (!isTaximeter)
        if (km <= parseFloat(distance) && ConfigGeneral().get("enable_floating_price_recalculation") == false)
            return parseFloat(price);

    const value =
        parseFloat(fare.km_price) * km +
        parseFloat(fare.minute_price) * parseInt(minute) +
        parseFloat(fare.base_price) +
        parseFloat(fare.another_fee) +
        parseFloat(fare.tax_price) +
        parseFloat(fare.waypoint_price) * tripWayPoints.length +
        checkTaxCancellationFee() +
        checkAdditionalValueKM(km, fare.km_to_additional_value, fare.additional_value_after_km, fare.type_additional_value_after_km);

    const newPrice = checkTripDiscountCoupon(checkMultiplierDynamic(value, multiplierDynamic),tripDiscountCoupon);
    const minPrice = checkTripDiscountCoupon(checkMultiplierDynamic(fare.min_price, multiplierDynamic), tripDiscountCoupon);

    if (newPrice < parseFloat(minPrice)) return minPrice;

    return newPrice;
}

function checkTripDiscountCoupon(value,tripDiscountCoupon){
    if(tripDiscountCoupon != null){
        switch (tripDiscountCoupon.valueType) {
            case "%":
                return value - (value * parseFloat(tripDiscountCoupon.value) / 100);
            case "$":
                return value - parseFloat(tripDiscountCoupon.value);
            default :
                return value;
        }
    }
    return value;
}

function checkAdditionalValueKM(km, km_to_additional_value, additional_value_after_km, type_additional_value_after_km) {
    if (parseFloat(km_to_additional_value) > 0)
        if (km >= parseFloat(km_to_additional_value)) {
            switch (type_additional_value_after_km) {
                case "km":
                    return (km - parseFloat(km_to_additional_value)) * parseFloat(additional_value_after_km);
                case "$":
                    return parseFloat(additional_value_after_km);
                default :
                    return 0;
            }
        }

    return 0;
}

function checkTaxCancellationFee() {
    const data = Session.get("valueCancellationFeeByCustomer");
    if (Array.isArray(data))
        return 0;

    return data.value;
}

function checkMultiplierDynamic(value, multiplierDynamic) {
    if (multiplierDynamic == null)
        return value;

    if (parseFloat(multiplierDynamic) === 0)
        return value;

    return value * parseFloat(multiplierDynamic);
}


function applyTravelCalculation(recalculate) {
    const trip = Session.get("tripDriver");

    PreloadRequest.progress("Sincronizando recalculo");

    TripController.recalculatePrice({
        tripReference: trip.tripReference,
        newPrice: parseFloat(recalculate.price),
        oldPrice: parseFloat(trip.price),
        newDistance: getKmRouteTraveled(),
        newTripTime: getMinutesRouteTraveled()
    }).then(({status}) => {
        if (!status) return errorChangeStatus();

        PreloadRequest.progress("Finalizando corrida");

        new DriverController()
            .finishTrip(trip.tripReference)
            .then(responseStatusTrip)
            .catch(finishTripOffline);
    });
}

function showChoiceCheckoutTrip(recalculate) {
    const trip = Session.get("tripDriver");

    document.querySelector(
        "#btnCheckoutTripOriginal"
    ).innerHTML = `<p>${getTextTranslate("trip", "text-choice-value-original")}(${parseInt(trip.distance)}km)</p>
        <h4><span>${CityConfig.getTypeCoin()}</span>${Mask.maskMoney(parseFloat(trip.price))}</h4>
        <label>(${getTextTranslate("trip", "text-choice-flat-rate")})</label>`;

    document.querySelector(
        "#btnCheckoutTripRecalculate"
    ).innerHTML = `<p>${getTextTranslate("trip", "text-choice-new-value")}(${parseInt(recalculate.km)}km)</p>
        <h4><span>${CityConfig.getTypeCoin()}</span>${Mask.maskMoney(parseFloat(recalculate.price))}</h4>
        <label>(${getTextTranslate("trip", "text-choice-recalculate")})</label>`;

    viewController.elementProperty.addClass(".container-checkout-trip", "active");

    viewController.elementProperty.addEventInElement(
        "#btnCheckoutTripOriginal",
        "onclick",
        () => {
            viewController.elementProperty.removeClass(
                ".container-checkout-trip",
                "active"
            );

            PreloadRequest.progress(getTextTranslate("trip", "progress-finish-trip"));

            new DriverController()
                .finishTrip(trip.tripReference)
                .then(responseStatusTrip)
                .catch(finishTripOffline);
        }
    );

    viewController.elementProperty.addEventInElement(
        "#btnCheckoutTripRecalculate",
        "onclick",
        () => {
            viewController.elementProperty.removeClass(
                ".container-checkout-trip",
                "active"
            );

            PreloadRequest.progress(getTextTranslate("trip", "progress-sync-recalculate"));

            TripController.recalculatePrice({
                tripReference: trip.tripReference,
                newPrice: parseFloat(recalculate.price),
                oldPrice: parseFloat(trip.price),
                newDistance: getKmRouteTraveled(),
                newTripTime: getMinutesRouteTraveled()
            }).then(({status}) => {
                if (!status) return errorChangeStatus();

                PreloadRequest.progress(getTextTranslate("trip", "success-finish-trip"));

                new DriverController()
                    .finishTrip(trip.tripReference)
                    .then(responseStatusTrip)
                    .catch(finishTripOffline);
            });
        }
    );
}
