import { world } from "@minecraft/server";
import vehiclesValues from "./vehicleValues.js";

export {
  takeoffSpeed,
  takeoffSpeedWater,
  takeOffFlight,
  takeOffFlightWater,
  vehicleCheck,
  vehicleSpeed,
  isAirInFrontAndBelow,
  isVehicleInWater,
  getEnvironment,
  applyAcceleration,
  setHoverState,
};

function takeoffSpeed(driver, vehicle, hasFuel, speed, vehicleData) {
  if (!hasFuel) {
    driver.setDynamicProperty("canTakeOff", false);
    return;
  }

  const canTakeOff = driver.getDynamicProperty("canTakeOff");

  if (speed == 0 && vehicle.isOnGround) {
    driver.onScreenDisplay.setActionBar("Hold Jump To Accelerate");
    driver.setDynamicProperty("canTakeOff", false);
  }
  if (speed > 0 && speed < vehicleData.take_off && vehicle.isOnGround) {
    driver.onScreenDisplay.setActionBar("Increase Speed To Take-Off");
    driver.setDynamicProperty("canTakeOff", false);
  }
  if (speed >= vehicleData.take_off && vehicle.isOnGround) {
    driver.onScreenDisplay.setActionBar("Look Up To Take-Off");
    driver.setDynamicProperty("canTakeOff", true);
  }
  /*   if (speed < vehicleData.take_off && !vehicle.isOnGround) {
    driver.onScreenDisplay.setActionBar(
      "Speed Dropping - Hold Jump To Avoid Falling"
    );
    driver.setDynamicProperty("canTakeOff", false);
  } */
  if (speed >= vehicleData.take_off * 0.7 && !vehicle.isOnGround) {
    driver.setDynamicProperty("canTakeOff", true);
  }

  return canTakeOff;
}

function takeoffSpeedWater(driver, vehicle, hasFuel, speed, vehicleData) {
  if (!hasFuel) {
    driver.setDynamicProperty("canTakeOff", false);
    return;
  }

  const canTakeOff = driver.getDynamicProperty("canTakeOff");

  // Function to check if the vehicle is in liquid
  const inLiquid = (vehicle) => {
    if (!vehicle) return false;
    if (vehicle?.location.y > 320) return false;

    const block = vehicle.dimension.getBlock({
      x: vehicle.location.x,
      y: vehicle.location.y - 1,
      z: vehicle.location.z,
    });
    return block?.isLiquid || false;
  };

  const isInLiquid = inLiquid(vehicle);
  const isOnGround = vehicle.isOnGround;
  if (isOnGround) {
    driver.onScreenDisplay.setActionBar(
      "The Seaplane Needs To Be On Water To Take Off"
    );
    driver.setDynamicProperty("canTakeOff", false);
  } else if (speed === 0 && isInLiquid) {
    driver.onScreenDisplay.setActionBar("Hold Jump To Accelerate");
    driver.setDynamicProperty("canTakeOff", false);
  } else if (speed > 0 && speed < vehicleData.take_off && isInLiquid) {
    driver.onScreenDisplay.setActionBar("Increase Speed To Take-Off");
    driver.setDynamicProperty("canTakeOff", false);
  } else if (speed >= vehicleData.take_off && isInLiquid) {
    driver.onScreenDisplay.setActionBar("Look Up To Take-Off");
    driver.setDynamicProperty("canTakeOff", true);
  } else if (speed >= vehicleData.take_off * 0.7 && !isInLiquid) {
    driver.setDynamicProperty("canTakeOff", true);
  }

  return canTakeOff;
}

// SWITCH MODE - if plane speed is enough, switch to flight
function takeOffFlight(driver, vehicle, hasFuel) {
  const takeOff = driver.getDynamicProperty("canTakeOff");
  const viewDirection = parseFloat(driver?.getViewDirection().y.toFixed(2));
  const events = [
    {
      condition: hasFuel && takeOff && viewDirection >= 0.5 && driver.isJumping, // player is jumping and moving upwards fast
      effect: "ascend_fast",
      amplifier: Math.floor(viewDirection * 0.35 * 100),
    },
    {
      condition:
        hasFuel &&
        takeOff &&
        viewDirection >= 0.2 &&
        viewDirection < 0.5 &&
        driver.isJumping, // player is jumping and moving upwards slowly
      effect: "ascend_slow",
      amplifier: viewDirection,
    },
    {
      condition:
        hasFuel &&
        takeOff &&
        viewDirection >= -0.2 &&
        viewDirection < 0.2 &&
        driver.isJumping, // player is jumping and holding altitude
      effect: "maintain",
    },
    {
      condition:
        hasFuel &&
        viewDirection >= -0.5 &&
        viewDirection < -0.2 &&
        driver.isJumping, // player is jumping and flying downwards slowly
      effect: "descend_slow",
      amplifier: 1,
    },
    {
      condition:
        hasFuel &&
        viewDirection < -0.5 &&
        viewDirection >= -0.8 &&
        driver.isJumping, // player is jumping and flying downwards fast
      effect: "descend_fast",
      amplifier: 0,
    },
    {
      condition: !driver.isJumping || !hasFuel,
      effect: "gliding",
      amplifier: 1, // Player is not jumping, or out of fuel - glide
    },
    { condition: viewDirection <= -0.8, effect: "descend_fall", amplifier: 0 }, // If player is looking straight down
  ];
  vehicle?.removeEffect("levitation");
  vehicle?.removeEffect("slow_falling");

  const { effect, amplifier } = events.find(({ condition }) => condition) || {};

  if (effect === "ascend_fast") {
    if (!vehicle.isOnGround) {
      driver.onScreenDisplay.setActionBar("Plane Ascending Fast");
    }
    vehicle?.addEffect("levitation", 20, {
      amplifier: amplifier,
      showParticles: false,
    });
  }
  if (effect === "ascend_slow") {
    if (!vehicle.isOnGround) {
      driver.onScreenDisplay.setActionBar("Plane Ascending");
    }
    const ascendValue = Math.max(0.08, Math.min(viewDirection / 2, 0.12));
    vehicle?.applyImpulse({ x: 0, y: ascendValue, z: 0 });
  }
  if (effect === "maintain") {
    vehicle?.applyImpulse({ x: 0, y: 0.0784, z: 0 });
    if (!vehicle.isOnGround) {
      driver.onScreenDisplay.setActionBar("Holding Altitude");
    }
  }
  if (effect == "descend_slow") {
    if (!vehicle.isOnGround) {
      driver.onScreenDisplay.setActionBar("Plane Descending");
    }
    vehicle?.addEffect("slow_falling", 20, {
      amplifier: amplifier,
      showParticles: false,
    });
  }
  if (effect == "descend_fast") {
    if (!vehicle.isOnGround) {
      driver.onScreenDisplay.setActionBar("Plane Descending Fast");
    }
    vehicle?.addEffect("slow_falling", 20, {
      amplifier: amplifier,
      showParticles: false,
    });
  }
  if (effect == "descend_fall") {
    if (!vehicle.isOnGround) {
      driver.onScreenDisplay.setActionBar("Plane Plummeting");
    }
    vehicle?.removeEffect("levitation");
    vehicle?.removeEffect("slow_falling");
  }
  if (effect == "gliding") {
    if (!vehicle.isOnGround) {
      driver.onScreenDisplay.setActionBar("Plane Gliding");
    }
    vehicle?.addEffect("slow_falling", 20, {
      amplifier: amplifier,
      showParticles: false,
    });
  }
}

function takeOffFlightWater(driver, vehicle, hasFuel) {
  const takeOff = driver.getDynamicProperty("canTakeOff");
  const viewDirection = parseFloat(driver?.getViewDirection().y.toFixed(2));
  const inLiquid = (vehicle) => {
    // checks if the entity is on the ground or in liquid.
    if (!vehicle) return false;
    if (vehicle?.location.y > 320) return false;
    const isLiquid = world
      .getDimension(dimensionIdObject[vehicle?.dimension.id])
      .getBlock({
        x: vehicle.location.x,
        y: vehicle.location.y - 1,
        z: vehicle.location.z,
      }).isLiquid;
    return isLiquid;
  };
  const events = [
    {
      condition: hasFuel && takeOff && viewDirection >= 0.5 && driver.isJumping, // player is jumping and moving upwards fast
      effect: "ascend_fast",
      amplifier: Math.floor(viewDirection * 0.35 * 100),
    },
    {
      condition:
        hasFuel &&
        takeOff &&
        viewDirection >= 0.2 &&
        viewDirection < 0.5 &&
        driver.isJumping, // player is jumping and moving upwards slowly
      effect: "ascend_slow",
      amplifier: viewDirection,
    },
    {
      condition:
        hasFuel &&
        takeOff &&
        viewDirection >= -0.2 &&
        viewDirection < 0.2 &&
        driver.isJumping, // player is jumping and holding altitude
      effect: "maintain",
    },
    {
      condition:
        hasFuel &&
        viewDirection >= -0.5 &&
        viewDirection < -0.2 &&
        driver.isJumping, // player is jumping and flying downwards slowly
      effect: "descend_slow",
      amplifier: 1,
    },
    {
      condition:
        hasFuel &&
        viewDirection < -0.5 &&
        viewDirection >= -0.8 &&
        driver.isJumping, // player is jumping and flying downwards fast
      effect: "descend_fast",
      amplifier: 0,
    },
    {
      condition: !driver.isJumping || !hasFuel,
      effect: "gliding",
      amplifier: 1, // Player is not jumping, or out of fuel - glide
    },
    { condition: viewDirection <= -0.8, effect: "descend_fall", amplifier: 0 }, // If player is looking straight down
  ];
  vehicle?.removeEffect("levitation");
  vehicle?.removeEffect("slow_falling");

  const { effect, amplifier } = events.find(({ condition }) => condition) || {};

  if (effect === "ascend_fast") {
    if (!inLiquid) {
      driver.onScreenDisplay.setActionBar("Plane Ascending Fast");
    }
    vehicle?.addEffect("levitation", 20, {
      amplifier: amplifier,
      showParticles: false,
    });
  }
  if (effect === "ascend_slow") {
    if (!inLiquid) {
      driver.onScreenDisplay.setActionBar("Plane Ascending");
    }
    const ascendValue = Math.max(0.08, Math.min(viewDirection / 2, 0.12));
    vehicle?.applyImpulse({ x: 0, y: ascendValue, z: 0 });
  }
  if (effect === "maintain") {
    vehicle?.applyImpulse({ x: 0, y: 0.0784, z: 0 });
    if (!inLiquid) {
      driver.onScreenDisplay.setActionBar("Holding Altitude");
    }
  }
  if (effect == "descend_slow") {
    if (!inLiquid) {
      driver.onScreenDisplay.setActionBar("Plane Descending");
    }
    vehicle?.addEffect("slow_falling", 20, {
      amplifier: amplifier,
      showParticles: false,
    });
  }
  if (effect == "descend_fast") {
    if (!inLiquid) {
      driver.onScreenDisplay.setActionBar("Plane Descending Fast");
    }
    vehicle?.addEffect("slow_falling", 20, {
      amplifier: amplifier,
      showParticles: false,
    });
  }
  if (effect == "descend_fall") {
    if (!inLiquid) {
      driver.onScreenDisplay.setActionBar("Plane Plummeting");
    }
    vehicle?.removeEffect("levitation");
    vehicle?.removeEffect("slow_falling");
  }
  if (effect == "gliding") {
    if (!inLiquid) {
      driver.onScreenDisplay.setActionBar("Plane Gliding");
    }
    vehicle?.addEffect("slow_falling", 20, {
      amplifier: amplifier,
      showParticles: false,
    });
  }
}

function setHoverState(driver, vehicle) {
  // sets the hoverstate if the player double taps the ascend button in a 75-300ms timeframe.
  let timeElapsed =
    driver.getDynamicProperty("end") - driver.getDynamicProperty("start");
  if (timeElapsed > 75 && timeElapsed < 300) {
    vehicle?.addTag("pb_plane_hovering");
    return true;
  } else {
    vehicle?.removeEffect("slow_falling");
    vehicle?.addEffect("levitation", 20, {
      amplifier: 5,
      showParticles: false,
    });
    vehicle?.removeTag("pb_plane_hovering");
    return false;
  }
}

function vehicleCheck(player) {
  const entityRidingOn =
    player.getComponent("minecraft:riding")?.entityRidingOn?.typeId;
  if (!entityRidingOn) return false;
  return Object.values(vehiclesValues).some(
    (vehicle) => vehicle.typeId === entityRidingOn
  );
}

function vehicleSpeed(vehicle) {
  const velocity = vehicle.getVelocity();
  return Math.sqrt(velocity.x ** 2 + velocity.z ** 2);
}

function applyAcceleration(vehicle, driver, impulseAmount) {
  const viewDirection = driver.getViewDirection();
  vehicle.applyImpulse({
    x: viewDirection.x * impulseAmount,
    y: 0,
    z: viewDirection.z * impulseAmount,
  });
}

function isAirInFrontAndBelow(vehicle, driver) {
  if (vehicle.location.y >= 300 || vehicle.location.y <= 5) {
    return false; // Default value when above altitude limit
  }
  const viewDirection = vehicle.getViewDirection();
  const x = Math.floor(vehicle.location.x + viewDirection.x);
  const y = Math.floor(vehicle.location.y);
  const z = Math.floor(vehicle.location.z + viewDirection.z);
  const blockAhead = vehicle.dimension.getBlock({ x, y, z });
  return blockAhead.typeId === "minecraft:air";
}

// Function to check if the vehicle is in water
function isVehicleInWater(vehicle) {
  const vehiclePosition = vehicle.location; // Get the vehicle's position
  const dimension = vehicle.dimension; // Get the dimension of the vehicle
  // Check the block directly below the vehicle
  const blockBelow = dimension.getBlock({
    x: Math.floor(vehiclePosition.x),
    y: Math.floor(vehiclePosition.y),
    z: Math.floor(vehiclePosition.z),
  });

  // Check if the block below is water
  return blockBelow && blockBelow.typeId === "minecraft:water";
}

// Function to check the environment (Ground, Water, or Air)
function getEnvironment(vehicle) {
  if (isVehicleInWater(vehicle)) {
    return "Water";
  } else if (vehicle.isOnGround) {
    return "Ground";
  } else {
    return "Air";
  }
}
