import { system, world, Player } from "@minecraft/server";
import { getVehicleStats } from "./spcrs_data";

const riddenCars = new Set();

// Utility to get or set the car state
const CarState = {
    IDLE: "idle",
    ACCELERATING_FORWARD: "accelerating_forward",
    ACCELERATING_BACKWARD: "accelerating_backward",
    BRAKING: "braking",
    OUT_OF_FUEL: "out_of_fuel"
};
function getCarState(car) {
    return car.getDynamicProperty("oct_spcrs:carState") ?? CarState.IDLE;
}
function setCarState(car, state) {
    car.setDynamicProperty("oct_spcrs:carState", state);
}


export function checkRiddenCars() {
    // Clear the current list of ridden cars
    riddenCars.clear();

    // Iterate over all players to check if they are riding a car
    world.getPlayers().forEach(player => {
        const ridingComponent = player.getComponent("minecraft:riding");
        if (ridingComponent) {
            try {
                const rideEntity = ridingComponent.entityRidingOn ?? undefined;
                if (rideEntity && rideEntity.typeId.startsWith("oct_spcrs:car_")) {
                    // Add the car entity to riddenCars set
                    riddenCars.add(ridingComponent.entityRidingOn);
                }
            } catch (error) {
                console.error("§cERROR: checking if player is riding a car:", error);
            }
        }
    });
}
export function runCarLogic() {
    if (riddenCars.size === 0) return;

    riddenCars.forEach(car => {
        if (!car.isValid()) return;

        const playerRiders = car.getComponent("minecraft:rideable")?.getRiders().filter(e => e instanceof Player);
        if (!playerRiders || playerRiders.length === 0) return;

        const movementComponent = car.getComponent("minecraft:movement");
        if (!movementComponent || !movementComponent.isValid()) return;

        // Fetch car settings
        const carId = car.typeId.replace("oct_spcrs:car_", "");
        let fuelDisabledSetting = false;
        let nitroDisabledSetting = false;

        // Ensure the carId is within a valid range
        if (!isNaN(carId) && carId >= 1 && carId <= 24) {
            // Fetch settings for valid carId
            const fuelSettings = JSON.parse(world.getDynamicProperty("oct_spcrs:setting.disable_fuel") || '[]');
            const nitroSettings = JSON.parse(world.getDynamicProperty("oct_spcrs:setting.disable_nitro") || '[]');

            // Use carId - 1 to get the correct index in the array
            fuelDisabledSetting = fuelSettings[carId - 1] ?? false;
            nitroDisabledSetting = nitroSettings[carId - 1] ?? false;
        } else {
            console.warn(`Invalid car ID: ${carId}. Falling back to default settings.`);
        }

        const velocity = car.getVelocity();
        const yaw = car.getRotation().y * (Math.PI / 180); // Convert yaw to radians
        const currentSpeed = (Math.sqrt(velocity.x ** 2 + velocity.z ** 2) * 100);
        const currentFuel = car.getDynamicProperty("oct_spcrs:fuel_level") ?? 0;

        // Convert world velocity to local space
        const localX = Math.cos(yaw) * velocity.x + Math.sin(yaw) * velocity.z;
        const localZ = -Math.sin(yaw) * velocity.x + Math.cos(yaw) * velocity.z;

        const inputThreshold = getVehicleStats(car.typeId).inputThreshold;
        const isPressingForward = localZ >= inputThreshold && Math.abs(localZ) >= Math.abs(localX);
        const isPressingBackward = localZ <= -inputThreshold && Math.abs(localZ) >= Math.abs(localX);

        // if (isPressingForward || isPressingBackward) {
        //     world.sendMessage(`§ca §8${localZ} §8${localX}`);
        // }

        // Handle movement logic
        const isBoosting = car.getDynamicProperty("oct_spcrs:is_boosting");
        const fuelConsumption = handleMovementInput(car, movementComponent, isPressingForward, isPressingBackward, currentSpeed, currentFuel, isBoosting, fuelDisabledSetting);
        const isDrifting = handleDrifting(car, localX, localZ);

        // if (isDrifting) {
        //     for (const player of playerRiders) {
        //         player.runCommand(`camerashake add @s 0.1 0.05 positional`);
        //     }
        // }

        let nitroBar = car.getDynamicProperty("oct_spcrs:nitro_bar") ?? 0;
        const nitroFillRate = getVehicleStats(car.typeId).nitroFillRate;
        const nitroDepletionRate = 4;

        if (!nitroDisabledSetting && isDrifting && nitroBar < 100 && system.currentTick % 4 === 0) {
            nitroBar = Math.min(100, nitroBar + nitroFillRate);
            car.setDynamicProperty("oct_spcrs:nitro_bar", nitroBar);
            //world.sendMessage(`§jNitro level: ${nitroBar.toFixed(0)}`);
        }

        if (!nitroDisabledSetting && playerRiders[0].isJumping && nitroBar > 0 && isPressingForward && system.currentTick % 4 === 0) {
            // world.sendMessage(`§8${car.name} got nitro!`);

            nitroBar = Math.max(0, nitroBar - nitroDepletionRate);
            car.setDynamicProperty("oct_spcrs:nitro_bar", nitroBar);

            for (const player of playerRiders) {
                player.runCommand(`camerashake add @s 0.1 0.05 positional`);
            }
        }

        if (!nitroDisabledSetting && playerRiders[0].isJumping && nitroBar > 0 && isPressingForward && !isBoosting) {
            car.setDynamicProperty("oct_spcrs:is_boosting", true);
            car.setProperty("oct_spcrs:anim.nitro", true);

            const yaw = car.getRotation().y * (Math.PI / 180);
            const futurePosition = getFuturePosition(car,
                currentSpeed,
                { x: Math.sin(yaw), y: 0, z: -Math.cos(yaw) }
            );

            world.playSound('oct_spcrs.car.nitro_start', futurePosition, { volume: 0.6 });
            if (getVehicleStats(car.typeId)?.isElectric) {
                world.playSound('oct_spcrs.car.electric_engine_boost', futurePosition, { volume: 0.5 });
            } else {
                world.playSound('oct_spcrs.car.engine_boost', futurePosition, { volume: 0.7 });
            }

        } else if ((!playerRiders[0].isJumping || nitroBar <= 0 || !isPressingForward) && isBoosting) {
            // world.sendMessage(`§8${car.name} lost nitro!`);
            car.setDynamicProperty("oct_spcrs:is_boosting", false);
            car.setProperty("oct_spcrs:anim.nitro", false);
        }

        // Show Actionbar UI
        const speedDisplay = currentSpeed > getVehicleStats(car.typeId).lateralMovementThreshold ? currentSpeed : 0;
        const currentState = isPressingForward ? "forward" : isPressingBackward ? "backward" : "stationary";
        const driftDirection = localX < 0 ? -1 : 1;
        showCarActionbar(car, playerRiders, speedDisplay, currentState, isDrifting, driftDirection, currentFuel, nitroBar, isBoosting, fuelDisabledSetting, nitroDisabledSetting);


        // Check for hit mobs
        const runOverSetting = world.getDynamicProperty('oct_spcrs:setting.disable_run_over');
        if (currentSpeed > 35 && !runOverSetting) {
            checkForHitMobs(car, 2, currentSpeed, { x: -Math.sin(yaw), z: Math.cos(yaw) });
        }

        const speedLinesSpeedTheshold = getVehicleStats(car.typeId).topSpeed - 40;
        const speedLinesThreshold = isDrifting ? speedLinesSpeedTheshold - 30 : speedLinesSpeedTheshold;
        if (!car.getProperty("oct_spcrs:anim.speed_lines") && currentSpeed >= speedLinesThreshold) {
            car.setProperty("oct_spcrs:anim.speed_lines", true);
        } else if (car.getProperty("oct_spcrs:anim.speed_lines") && currentSpeed < speedLinesThreshold) {
            car.setProperty("oct_spcrs:anim.speed_lines", false);
        }

        // handle fuel consumption
        if (!fuelDisabledSetting && currentFuel > 0 && system.currentTick % 60 === 0) {
            const newFuel = Math.max(0, currentFuel - fuelConsumption);
            car.setDynamicProperty("oct_spcrs:fuel_level", newFuel);
            //world.sendMessage(`§jFuel level: ${newFuel.toFixed(0)}`);
        }

    });
}
/*
function handleMovementInput(car, movementComponent, isPressingForward, isPressingBackward, currentSpeed) {
    const { backwardSpeedMultiplier, accelerationDampeningPower, baseAcceleration } = getVehicleStats(car.typeId);

    // Define the maximum forward speed based on the effective max of the movement component
    const maxForwardSpeed = movementComponent.effectiveMax;
    const backwardSpeed = maxForwardSpeed * backwardSpeedMultiplier; // Define backward speed

    // Check if the car is currently moving forward
    if (isPressingForward) {
        // Gradually increase speed
        if (movementComponent.currentValue < maxForwardSpeed) {
            const acceleration = calculateDynamicAcceleration(movementComponent.currentValue, accelerationDampeningPower, baseAcceleration, maxForwardSpeed);
            movementComponent.setCurrentValue(Math.min(movementComponent.currentValue + acceleration, maxForwardSpeed));
        }

        // Handle reverse animation
        if (car.getProperty("oct_spcrs:anim.reverse")) {
            car.setProperty("oct_spcrs:anim.reverse", false);
        }

        // handle sound
        if (system.currentTick % 20 === 0 && currentSpeed > 40) {
            world.playSound('oct_spcrs.car.engine_drive_fast', car.location, { volume: 1.0 });
            world.playSound('oct_spcrs.car.engine_idle', car.location, { volume: 1.0 });
        } else if (system.currentTick % 20 === 0) {
            world.playSound('oct_spcrs.car.engine_drive_slow', car.location, { volume: 1.0 });
            world.playSound('oct_spcrs.car.engine_idle', car.location, { volume: 1.0 });
        }

        if (car.getDynamicProperty("oct_spcrs:anim.rev") ?? true) {
            world.playSound('octovon.spcrs.delivery_car.engine.rev', car.location, { volume: 1.0 });
            car.setDynamicProperty("oct_spcrs:anim.rev", false);
        }

    } else if (isPressingBackward) {
        // reset speed if going faster
        // if (movementComponent.currentValue > backwardSpeed) {
        //     movementComponent.resetToDefaultValue();
        // }

        // Set speed for backward movement
        if (movementComponent.currentValue !== backwardSpeed) {
            const acceleration = calculateDynamicAcceleration(movementComponent.currentValue, accelerationDampeningPower, baseAcceleration, maxForwardSpeed);
            movementComponent.setCurrentValue(Math.min(movementComponent.currentValue + acceleration, backwardSpeed));
        }

        // Handle reverse animation
        if (!car.getProperty("oct_spcrs:anim.reverse")) {
            car.setProperty("oct_spcrs:anim.reverse", true);
        }

        // handle sound
        if (system.currentTick % 20 === 0) {
            world.playSound('oct_spcrs.car.engine_drive_slow', car.location, { volume: 1.0 });
            world.playSound('oct_spcrs.car.engine_idle', car.location, { volume: 1.0 });
        }

        if (!car.getDynamicProperty("oct_spcrs:anim.rev") ?? false) {
            car.setDynamicProperty("oct_spcrs:anim.rev", true)
        };

    } else {
        // Reset to default value when not pressing forward or backward
        if (movementComponent.currentValue !== movementComponent.defaultValue) {
            movementComponent.resetToDefaultValue();
        }

        // Handle reverse animation
        if (car.getProperty("oct_spcrs:anim.reverse")) {
            car.setProperty("oct_spcrs:anim.reverse", false);
        }

        // handle sound
        if (system.currentTick % 20 === 0) {
            world.playSound('oct_spcrs.car.engine_idle', car.location, { volume: 1.0 });
        }

        if (!car.getDynamicProperty("oct_spcrs:anim.rev") ?? false) {
            car.setDynamicProperty("oct_spcrs:anim.rev", true)
        };
    }
}
*/

function handleMovementInput(car, movementComponent, isPressingForward, isPressingBackward, currentSpeed, currentFuel, isBoosting = false, fuelDisabled = false) {
    const state = getCarState(car);
    const soundKeys = getVehicleStats(car?.typeId).soundKeys;
    let fuelConsumption = 0;
    const breakSpeedTrigger = 10;

    // Retrieve or initialize the previous speed
    // const previousSpeed = car.getDynamicProperty("oct_spcrs:prevSpeed") ?? 0;
    // const decelerationRate = 0.2; // Adjust as necessary for desired deceleration speed

    // Deceleration logic: if current speed is less than the previous speed, apply deceleration
    // if (currentSpeed < previousSpeed) {
    //     world.sendMessage(`Deceleration: ${movementComponent.currentValue}`);
    //     if (state === CarState.ACCELERATING_FORWARD) {
    //         // Apply deceleration when moving forward
    //         movementComponent.setCurrentValue(Math.max(movementComponent.currentValue - decelerationRate, movementComponent.defaultValue));
    //     } else if (state === CarState.ACCELERATING_BACKWARD) {
    //         // Apply deceleration when moving backward
    //         movementComponent.setCurrentValue(Math.min(movementComponent.currentValue + decelerationRate, movementComponent.defaultValue));
    //     }
    // }

    if (currentFuel <= 0 && !fuelDisabled) {
        setCarState(car, CarState.OUT_OF_FUEL);
    } else {
        if (state === CarState.OUT_OF_FUEL) {
            setCarState(car, CarState.IDLE);
        }
    }


    switch (state) {
        case CarState.IDLE:
            if (isPressingForward) {
                // world.sendMessage(`§ca`);
                setCarState(car, CarState.ACCELERATING_FORWARD);
            } else if (isPressingBackward) {
                // world.sendMessage(`§ca`);
                setCarState(car, CarState.ACCELERATING_BACKWARD);
            } else {
                fuelConsumption = 1;
                if (system.currentTick % 20 === 0) {
                    world.playSound(soundKeys.engineIdle, car.location, { volume: 1.0 });
                }
            }
            break;

        case CarState.ACCELERATING_FORWARD:
            //if (!isPressingForward && currentSpeed <= breakSpeedTrigger) { // Add speed condition to fix sharp turn stalling issue
            // This enables crab walking when above the break trigger
            if (!isPressingForward) {
                setCarState(car, CarState.BRAKING);
            } else if (isPressingBackward) {
                setCarState(car, CarState.BRAKING);
                movementComponent.resetToDefaultValue();
            } else {
                fuelConsumption = 2;
                accelerateForward(car, movementComponent, currentSpeed);

                const yaw = car.getRotation().y * (Math.PI / 180);
                const futurePosition = getFuturePosition(car,
                    currentSpeed,
                    { x: Math.sin(yaw), y: 0, z: -Math.cos(yaw) }
                );

                if (system.currentTick % 20 === 0) {
                    if (currentSpeed > 50) {
                        world.playSound(soundKeys.driveFast, futurePosition, { volume: 1.0 });
                        world.playSound(soundKeys.engineIdle, futurePosition, { volume: 1.0 });

                    } else {
                        world.playSound(soundKeys.driveSlow, car.location, { volume: 1.0 });
                        world.playSound(soundKeys.engineIdle, car.location, { volume: 1.0 });
                    }
                }

                if (isBoosting && system.currentTick % 2 === 0) {
                    if (currentSpeed > 50) {
                        world.playSound('oct_spcrs.car.nitro_loop', futurePosition, { volume: 0.1 });
                    } else {
                        world.playSound('oct_spcrs.car.nitro_loop', car.location, { volume: 0.1 });
                    }
                }
            }
            break;

        case CarState.ACCELERATING_BACKWARD:
            if (!isPressingBackward) {
                setCarState(car, CarState.BRAKING);
            } else if (isPressingForward) {
                setCarState(car, CarState.BRAKING);
                movementComponent.resetToDefaultValue();
            } else {
                fuelConsumption = 2;
                accelerateBackward(car, movementComponent, currentSpeed);
                if (system.currentTick % 20 === 0) {
                    world.playSound(soundKeys.driveSlow, car.location, { volume: 1.0 });
                    world.playSound(soundKeys.engineIdle, car.location, { volume: 1.0 });
                }
            }
            break;

        case CarState.BRAKING:
            // Reset speed
            if (movementComponent.currentValue > movementComponent.defaultValue) {
                movementComponent.resetToDefaultValue();
                // world.sendMessage(`§cBraking!`);

            } else if (movementComponent.currentValue === movementComponent.defaultValue) {
                // Transition to the appropriate state based on input
                if (isPressingForward) {
                    setCarState(car, CarState.ACCELERATING_FORWARD);
                } else if (isPressingBackward) {
                    setCarState(car, CarState.ACCELERATING_BACKWARD);
                } else {
                    setCarState(car, CarState.IDLE);
                }
            }
            break;

        case CarState.OUT_OF_FUEL:
            fuelConsumption = 0;
            if (movementComponent.currentValue !== movementComponent.defaultValue) {
                movementComponent.resetToDefaultValue();
            }
            break;
    }

    // Trigger the break animation if it's preped and the car slowed down
    if (!car.getProperty("oct_spcrs:anim.break") && currentSpeed <= breakSpeedTrigger) {
        car.setProperty("oct_spcrs:anim.break", true);
        world.playSound('oct_spcrs.car.tires_squal', car.location, { volume: 0.6 });
    }

    // Update the previous speed property
    car.setDynamicProperty("oct_spcrs:prevSpeed", currentSpeed);

    return fuelConsumption;
}
function accelerateForward(car, movementComponent, currentSpeed) {
    const { accelerationDampeningPower, baseAcceleration } = getVehicleStats(car.typeId);
    const isBoosting = car.getDynamicProperty("oct_spcrs:is_boosting");
    const maxForwardSpeed = isBoosting ? 10000 : movementComponent.effectiveMax - 0.08; // Max forward speed

    if (movementComponent.currentValue < maxForwardSpeed) {
        // Compute dynamic acceleration
        const acceleration = calculateDynamicAcceleration(
            movementComponent.currentValue,
            accelerationDampeningPower,
            baseAcceleration,
            maxForwardSpeed
        );

        // Update the speed
        movementComponent.setCurrentValue(Math.min(
            movementComponent.currentValue + acceleration,
            maxForwardSpeed
        ));
    } else {
        movementComponent.setCurrentValue(maxForwardSpeed);
    }

    if (car.getProperty("oct_spcrs:anim.break") && currentSpeed > 70) {
        car.setProperty("oct_spcrs:anim.break", false);
    }

    // Handle reverse animation
    if (car.getProperty("oct_spcrs:anim.reverse")) {
        car.setProperty("oct_spcrs:anim.reverse", false);
    }

}
function accelerateBackward(car, movementComponent, currentSpeed) {
    const { accelerationDampeningPower, baseBackwardsAcceleration, backwardSpeedMultiplier } = getVehicleStats(car.typeId);
    const maxForwardSpeed = movementComponent.effectiveMax; // Max forward speed
    const maxBackwardSpeed = maxForwardSpeed * backwardSpeedMultiplier; // Backward speed limit

    if (movementComponent.currentValue < maxBackwardSpeed) {
        // Compute dynamic acceleration
        const acceleration = calculateDynamicAcceleration(
            movementComponent.currentValue,
            accelerationDampeningPower,
            baseBackwardsAcceleration,
            maxForwardSpeed
        );

        // Update the speed
        movementComponent.setCurrentValue(Math.min(
            movementComponent.currentValue + acceleration,
            maxBackwardSpeed
        ));
    } else {
        movementComponent.setCurrentValue(maxBackwardSpeed);
    }

    // Handle reverse animation
    if (!car.getProperty("oct_spcrs:anim.reverse")) {
        car.setProperty("oct_spcrs:anim.reverse", true);
    }
}
function calculateDynamicAcceleration(currentSpeed, accelerationDampeningPower, baseAcceleration, maxForwardSpeed) {
    // Normalize the current speed to a 0-1 range
    const normalizedSpeed = currentSpeed / maxForwardSpeed;

    // Create an acceleration factor that accelerates faster at the start and slows down at the top speed
    // Use a power greater than 1 (e.g., 1.5 or 2) to create this effect
    const accelerationFactor = Math.pow(1 - normalizedSpeed, accelerationDampeningPower);

    // Calculate the dynamic acceleration
    const dynamicAcceleration = baseAcceleration * accelerationFactor;

    // Ensure dynamicAcceleration does not go below 0
    return Math.max(dynamicAcceleration, 0);
}

function handleDrifting(car, localX, localZ,) {
    const isMovingSideways = Math.abs(localX) > getVehicleStats(car.typeId).lateralMovementThreshold;
    const driftProp = car.getProperty("oct_spcrs:anim.drift");
    let isDrifting = false;

    if (isMovingSideways && localZ >= getVehicleStats(car.typeId).driftThreshold) {
        const curRotation = car.getRotation();
        const turnDirection = localX < 0 ? -1 : 1;
        const driftAngle = getVehicleStats(car.typeId).driftAngle;
        const addedRotation = driftAngle * turnDirection;
        const adjustedRotation = { x: curRotation.x, y: curRotation.y + addedRotation, z: curRotation.z };
        car.setRotation(adjustedRotation);
        isDrifting = true;

        if (!driftProp) {
            car.setProperty("oct_spcrs:anim.drift", true);
        }
        // handle sound
        if (system.currentTick % 4 === 0) {
            world.playSound('oct_spcrs.car.tires_squal', car.location, { volume: 0.5, pitch: Math.random() * 0.1 + 0.9 });
        }

    } else if (driftProp) {
        car.setProperty("oct_spcrs:anim.drift", false);
    }

    // [NOT NEEDED]
    // //Drift correction logic
    // const driftAngle = Math.atan2(localX, localZ) * (180 / Math.PI); // Calculate the drift angle in degrees
    // if (Math.abs(driftAngle) > 15) {
    //     const correctionRotation = 0.001 * (driftAngle > 0 ? 1 : -1);
    //     const curRotation = car.getRotation();
    //     const newRotation = { x: curRotation.x, y: curRotation.y + correctionRotation, z: curRotation.z };
    //     car.setRotation(newRotation);
    // }

    return isDrifting;
}
function showCarActionbar(car, playerRiders, speedDisplay, currentState, isDrifting, driftDirection, currentFuel = 0, nitroBar = 0, isBoosting = false, fuelDisabled = false, nitroDisabled = false) {
    const topSpeed = getVehicleStats(car.typeId).topSpeed;
    const isElectric = getVehicleStats(car.typeId)?.isElectric || false;

    // Calculate the number of filled bars
    const totalBars = 10;
    const totalFuelBars = 5;
    const filledSpeedBarsCount = Math.ceil((speedDisplay / topSpeed) * totalBars);
    const filledNitroBarsCount = Math.ceil((nitroBar / 100) * totalBars);
    const filledFuelBarsCount = Math.ceil((currentFuel / 500) * totalFuelBars);

    // Define color thresholds
    const speedColors = [
        { threshold: 0.5, color: "§q" },
        { threshold: 0.8, color: "§p" },
        { threshold: 0.9, color: "§n" },
        { threshold: 1.0, color: "§m" }
    ];
    const fuelColors = [
        { threshold: 0.2, color: "§m" },
        { threshold: 0.4, color: "§n" },
        { threshold: 1.0, color: `${isElectric ? "§2" : "§7"}` }
    ];

    const movementStateSelector = (isDrifting, driftDirection, currentState) => {
        if (isDrifting) {
            return driftDirection > 0 ? "§c<<" : "§c>>";
        }
        switch (currentState) {
            case "forward":
                return "§8^";
            case "backward":
                return "§mR";
            default:
                return "§r";
        }
    };

    // Build the speed meter string with color-coded filled bars
    let speedMeter = "";
    for (let i = 0; i < totalBars; i++) {
        const fillRatio = (i + 1) / totalBars;
        const color = speedColors.find(c => fillRatio <= c.threshold).color;
        speedMeter += i < filledSpeedBarsCount ? `${color}▒` : "§8▒";
    }

    let blinkEmptyFuel = currentFuel <= 0 && system.currentTick % 8 === 0;

    // Build the fuel meter string with color-coded filled bars
    let fuelMeter = "";
    for (let i = 0; i < totalFuelBars; i++) {
        const fillRatio = (i + 1) / totalFuelBars;
        const color = fuelColors.find(c => fillRatio <= c.threshold).color;
        fuelMeter += i < filledFuelBarsCount ? `${color}■` : `${blinkEmptyFuel ? "§m" : "§8"}■`;
    }

    // Build the fuel meter string with color-coded filled bars
    let nitroMeter = "";
    for (let i = 0; i < totalBars; i++) {
        nitroMeter += i < filledNitroBarsCount ? `${isBoosting ? "§b" : "§9"}▀` : "§8▀";
    }

    let fuelDisplay = `§r§o     ${blinkEmptyFuel ? "§m" : "§8"}E${fuelMeter} ${blinkEmptyFuel ? "§m" : "§8"}F`;
    let batteryDisplay = `§r§o${fuelMeter} ${blinkEmptyFuel ? "§m" : "§8"}${((currentFuel / 500) * 100).toFixed(0)}%`;

    // Show title info to all player riders
    const rawSpeedDisplay = {
        rawtext: [
            {
                "text": `§f${speedDisplay.toFixed(0)} ${movementStateSelector(isDrifting, driftDirection, currentState)}`
            },
            {
                "text": `\n§r§o${speedMeter}`
            },
            {
                "text": `${nitroDisabled ? "" : `\n${nitroMeter}`}`
            },
            {
                "text": `${fuelDisabled ? "" : `\n${isElectric ? batteryDisplay : fuelDisplay}`}`
            }
        ]
    };
    for (const rider of playerRiders) {
        // check player setting
        const playerSetting = rider.getDynamicProperty('oct_spcrs:setting.disable_speedometer');
        if (!playerSetting) {
            rider.runCommand(`titleraw @s actionbar ${JSON.stringify(rawSpeedDisplay)}`);
        }
    }
}
export function updatePlayerRidingStatus() {
    for (const player of world.getPlayers()) {
        let isRidingcar = false;
        const ridingComponent = player.getComponent("minecraft:riding");
        if (ridingComponent) {
            try {
                const rideEntity = ridingComponent.entityRidingOn ?? undefined;
                if (rideEntity && rideEntity.typeId.startsWith("oct_spcrs:car_")) {
                    // world.sendMessage(`§e${player.name} riding a car.`);
                    isRidingcar = true;
                }
            } catch (error) {
                console.error(`§cERROR: updating player riding status:\n${error}`);
            }
        }

        // If the player stopped riding the car
        if (!isRidingcar && player.getDynamicProperty('oct_spcrs:is_riding_car')) {
            // world.sendMessage(`§8${player.name} got reset.`);
            player.camera.clear();
            player.setDynamicProperty('oct_spcrs:is_riding_car', false);
            player.setDynamicProperty('oct_spcrs:follow_orbit_camera', undefined);
        }
    }
}
export function toggleOrbitCamera(player) {

    if (player.getDynamicProperty('oct_spcrs:follow_orbit_camera')) {
        player.camera.clear();
        player.setDynamicProperty('oct_spcrs:follow_orbit_camera', undefined);

    } else {
        player.camera.setCamera("minecraft:follow_orbit");
        player.setDynamicProperty('oct_spcrs:follow_orbit_camera', true);
    }

}
function getFuturePosition(car, speed = 0, direction = { x: 0, y: 0, z: 0 }, timeOffset = 0.1) {
    // world.sendMessage(`Speed: ${speed.toFixed(2)}, Direction: §c${direction.x.toFixed(1)} §2${direction.y.toFixed(1)} §9${direction.z.toFixed(1)}`);

    // Calculate the future position of the car after `timeOffset` seconds
    const futurePosition = {
        x: car.location.x + direction.x * speed * timeOffset,
        y: car.location.y, // Maintain current Y position (no vertical offset)
        z: car.location.z + direction.z * speed * timeOffset,
    };

    return futurePosition;
}
function checkForHitMobs(car, range, currentSpeed, forwardDirection) {
    const entitiesInRange = car.dimension.getEntities({
        location: car.location,
        maxDistance: range
    }).filter(e =>
        e.isValid() &&
        e.getComponent('minecraft:item') === undefined &&
        (e.typeId.startsWith("minecraft:") || e.getComponent("type_family")?.hasTypeFamily('mob')) &&
        e.id !== car.id &&
        !(e instanceof Player)
    );

    const maxKnockbackStrength = 10; // Maximum horizontal knockback strength at top speed
    const maxVerticalStrength = 0.5; // Maximum vertical knockback strength
    const maxDamage = 5; // Maximum damage
    const speedFactor = Math.min(currentSpeed / 100, 1); // Scale speed to a 0-1 range

    if (entitiesInRange.length > 0) {
        // console.info(`Detected ${entitiesInRange.length} mob(s) near the car at ${car.location}`);
        entitiesInRange.forEach(entity => {
            // Check if recently damaged
            const prevHitTime = entity.getDynamicProperty('oct_spcrs:prev_car_hit_time');
            if (prevHitTime && system.currentTick - prevHitTime < 20) {
                return;
            };
            entity.setDynamicProperty('oct_spcrs:prev_car_hit_time', system.currentTick);

            // Apply proportional damage
            const damageAmount = Math.ceil(maxDamage * speedFactor);
            entity.applyDamage(damageAmount);

            if (!entity.isValid()) return; // return if killed

            // Calculate knockback strengths based on current speed
            const horizontalStrength = maxKnockbackStrength * speedFactor;
            const verticalStrength = maxVerticalStrength * speedFactor;

            // Apply knockback to the entity in the car's forward direction
            entity?.applyKnockback(
                forwardDirection.x, // Car's forward X direction
                forwardDirection.z, // Car's forward Z direction
                horizontalStrength,
                verticalStrength
            );

        });
    }
}