import { system, world, ItemStack } from "@minecraft/server";

const TICKS_PER_DAY = 24000;
const RED_MOON_START_TOD = 12500;
const FULL_MOON_PHASE = 4;

// Configuration: Mob Type → Array of item drops with min/max
const redMoonCustomDrops = {
  "hb_hr:death_moth": [
    { itemType: "hb_hr:soul_piece", min: 1, max: 2 },
    { itemType: "minecraft:rotten_flesh", min: 1, max: 2 },
  ],
  "hb_hr:screamer": [
    { itemType: "hb_hr:soul_piece", min: 3, max: 6 },
    { itemType: "hb_hr:screamer_cable", min: 1, max: 1 },
    { itemType: "minecraft:redstone", min: 2, max: 4 },
    { itemType: "minecraft:bone", min: 2, max: 4 },
  ],
  "hb_hr:lost_soul": [{ itemType: "hb_hr:soul_piece", min: 1, max: 2 }],
  "hb_hr:scared_chicken": [
    { itemType: "hb_hr:soul_piece", min: 1, max: 2 },
    { itemType: "minecraft:feather", min: 1, max: 2 },
    { itemType: "minecraft:chicken", min: 1, max: 2 },
  ],
  "hb_hr:scared_cow": [
    { itemType: "hb_hr:soul_piece", min: 1, max: 2 },
    { itemType: "minecraft:leather", min: 1, max: 2 },
    { itemType: "minecraft:beef", min: 1, max: 2 },
  ],
  "hb_hr:scared_pig": [
    { itemType: "hb_hr:soul_piece", min: 1, max: 2 },
    { itemType: "minecraft:porkchop", min: 1, max: 2 },
  ],
  "hb_hr:scared_sheep": [
    { itemType: "hb_hr:soul_piece", min: 1, max: 2 },
    { itemType: "minecraft:porkchop", min: 1, max: 2 },
  ],
  "hb_hr:agressive_lost_soul": [
    { itemType: "hb_hr:soul_piece", min: 1, max: 2 },
    { itemType: "hb_hr:soul_sheet", min: 1, max: 2 },
  ],
  "hb_hr:undead_villager": [{ itemType: "hb_hr:soul_piece", min: 1, max: 2 }],
  "hb_hr:undead_golem": [
    { itemType: "hb_hr:soul_piece", min: 1, max: 2 },
    { itemType: "minecraft:iron_ingot", min: 2, max: 4 },
  ],
  "hb_hr:faceless_pillager_large": [
    { itemType: "hb_hr:soul_piece", min: 2, max: 3 },
    { itemType: "minecraft:iron_nugget", min: 1, max: 2 },
  ],
  "hb_hr:faceless_pillager_medium": [
    { itemType: "hb_hr:soul_piece", min: 1, max: 2 },
    { itemType: "minecraft:iron_nugget", min: 1, max: 2 },
  ],
  "hb_hr:faceless_pillager_small": [
    { itemType: "hb_hr:soul_piece", min: 1, max: 2 },
    { itemType: "minecraft:iron_nugget", min: 1, max: 2 },
  ],
};
const redMoonMobConfig = [
  // { id: "minecraft:ghast", event: null },
  // { id: "minecraft:blaze", event: null },
  { id: "minecraft:wither_skeleton", event: null },
  { id: "hb_hr:death_moth", event: null },
  { id: "hb_hr:scared_chicken", event: "hb_hr:red_moon_spawn" },
  { id: "hb_hr:scared_cow", event: "hb_hr:red_moon_spawn" },
  { id: "hb_hr:scared_pig", event: "hb_hr:red_moon_spawn" },
  { id: "hb_hr:scared_sheep", event: "hb_hr:red_moon_spawn" },
  { id: "hb_hr:faceless_pillager_large", event: null },
  { id: "hb_hr:faceless_pillager_medium", event: null },
  { id: "hb_hr:faceless_pillager_small", event: null },
];
const playersInWater = new Map();
const FULL_MOON_SLEEP_PERCENTAGE = 101;
const NORMAL_SLEEP_PERCENTAGE = 100;

export class moonHandler {
  static initialized = false;
  static playerBiomeMap = new Map(); // Speichert zuletzt erkannte Biome für jeden Spieler

  constructor() {
    this.initialize();
  }

  initialize() {
    if (!moonHandler.initialized) {
      moonHandler.initialized = true;
      this.processSubscriptions();
    }
  }

  processSubscriptions() {
    let curTick = 0;
    const INIT_TIME = 0;

    system.afterEvents.scriptEventReceive.subscribe((event) => {
      const source = event.sourceEntity;
      if (source?.typeId !== "minecraft:player") return;

      if (event.id === "hb_hr:start_red_moon") {
        let ticksToRedMoon = getTicksUntilNextRedMoon();
        // world.sendMessage(ticksToRedMoon.toString());
        source.runCommand("/time add " + ticksToRedMoon);
      }
    });

    world.afterEvents.playerSpawn.subscribe((event) => {
      const playerMoonTag = "hb_hr:" + event.player.id;
      event.player.runCommand("/event entity @e[type=hb_hr:red_moon,tag=" + playerMoonTag + "] hb_hr:despawn");
      let velocity = event.player.getVelocity();
      let loc = {
        x: event.player.location.x,
        y: event.player.location.y + (event.player.isSneaking ? 1.3 : 1.6),
        z: event.player.location.z,
      };
      const allMoons = event.player.dimension.getEntities({ type: "hb_hr:red_moon", tags: [playerMoonTag] });
      try {
        if (allMoons.length > 0 || !allMoons) {
          allMoons.forEach((moon) => {
            if (!moon.isValid()) return;
            moon.teleport(loc);
            moon.applyImpulse(velocity);

            /*if (!moon.getComponent(EntityComponentTypes.Riding)) {
              const rideable = player.getComponent(EntityComponentTypes.Rideable);

              rideable?.ejectRiders();
              rideable?.addRider(moon);
            }*/
            moon.playAnimation("animation.hb_hr.red_moon.turn_on", { players: [player.name] });
            moon.addTag("moon_on");
          });
        } else {
          let newMoon = event.player.dimension.spawnEntity("hb_hr:red_moon", loc);
          newMoon.addTag(playerMoonTag);
        }
      } catch (error) {}
    });

    world.afterEvents.entityDie.subscribe((event) => {
      const { deadEntity } = event;
      const mobType = deadEntity.typeId;
      if (!deadEntity) return;
      if (!deadEntity.isValid()) return;
      if (!isRedMoon() && deadEntity.dimension.id != "overworld") return;

      if (!redMoonCustomDrops[mobType]) return;

      const location = deadEntity.location;
      const dimension = deadEntity.dimension;

      for (const drop of redMoonCustomDrops[mobType]) {
        const amount = Math.floor(Math.random() * (drop.max - drop.min + 1)) + drop.min;
        if (amount <= 0) continue;

        const itemStack = new ItemStack(drop.itemType, amount);
        try {
          dimension.spawnItem(itemStack, location);
        } catch (error) {}
      }
    });

    system.runInterval(() => {
      try {
        if (curTick > INIT_TIME) {
          const allPlayers = world.getAllPlayers();
          allPlayers.forEach((player) => {
            if (!player.isValid()) return;
            if (!isRedMoon() && player.dimension.id != "overworld") return;
            this.handleMoonSleep(player, curTick);
          });
        }
        curTick++;
      } catch (e) {
        // console.warn(e);
      }
    }, 20);

    system.runInterval(() => {
      try {
        if (curTick > INIT_TIME) {
          const allPlayers = world.getAllPlayers();
          allPlayers.forEach((player) => {
            if (!player.isValid()) return;

            this.handleMoonClock(player);
            if (!isRedMoon() && player.dimension.id != "overworld") return;
            this.handleMoonDisplay(player, curTick);
            this.handleHunger(player);
            this.handleMobSpawn(player);
            this.handleWaterSlowness(player);
          });
        }
        curTick++;
      } catch (e) {
        // console.warn(e);
      }
    }, 1);
  }

  handleHunger(player) {
    if (system.currentTick % 20 == 0) player.addEffect("hunger", 40, { amplifier: 4 });
  }
  handleMobSpawn(player) {
    if (system.currentTick % 20 == 0) {
      player.runCommand("event entity @e[r=100,family=hb_hr_scared_mob,tag=!hb_hr:red_moon_entity] hb_hr:start_transform");
      player.runCommand("tag @e[r=100,family=hb_hr_scared_mob,tag=!hb_hr:red_moon_entity] add hb_hr:red_moon_entity");
    }
    if (system.currentTick % 100 === 0) {
      const nearbyEntities = player.dimension.getEntities({
        location: player.location,
        tags: ["hb_hr:red_moon_entity"],
        excludeTypes: ["minecraft:item"],
        maxDistance: 50,
      });
      if (nearbyEntities.length >= 20) return;

      const herdCount = Math.floor(Math.random() * 3) + 1;
      for (let herd = 0; herd < herdCount; herd++) {
        const herdSize = Math.floor(Math.random() * 3) + 1;

        // 2.1 Choose a random mob entry from the array
        const randomIndex = Math.floor(Math.random() * redMoonMobConfig.length);
        const { id: mobType, event: spawnEvent } = redMoonMobConfig[randomIndex];

        // (c) Determine a central spawn position for the herd
        const herdSpawnLocation = getRandomSpawnLocationNearPlayer(player);
        if (!herdSpawnLocation) continue;

        for (let i = 0; i < herdSize; i++) {
          // (d) Generate random offset coordinates around the herd position
          const offsetX = (Math.random() - 0.5) * 2;
          const offsetZ = (Math.random() - 0.5) * 2;
          const spawnLocation = {
            x: herdSpawnLocation.x + offsetX,
            y: herdSpawnLocation.y,
            z: herdSpawnLocation.z + offsetZ,
          };

          // 2.2 Build spawn options dynamically
          let moonEntity;
          if (spawnEvent) {
            moonEntity = player.dimension.spawnEntity(mobType + "<" + spawnEvent + ">", spawnLocation);
          } else {
            moonEntity = player.dimension.spawnEntity(mobType, spawnLocation);
          }
          // (Optional: You could set initialPersistence or initialRotation here)

          // (e) Spawn the mob
          moonEntity.addTag("hb_hr:red_moon_entity");

          // If a spawnEvent is specified, the API will automatically send
          // exactly that event to the new entity after creation. If no
          // spawnEvent is defined, nothing further happens here.
        }
      }
    }
  }
  handleWaterSlowness(player) {
    const block = player.dimension.getBlock(player.location);
    const isInWater = block?.typeId === "minecraft:water" || block?.typeId === "minecraft:flowing_water";

    const wasInWater = playersInWater.get(player.id) || false;

    if (wasInWater && !isInWater) {
      // Player just left water — apply slowness
      player.addEffect("slowness", 100, { amplifier: 0, showParticles: false });
    }

    // Update tracking
    playersInWater.set(player.id, isInWater);
  }
  handleMoonSleep(player, curTick) {
    const dimension = world.getDimension(player.dimension.id);
    if (dimension.id != "minecraft:overworld") return;
    const timeOfDay = world.getTimeOfDay();
    const moonPhase = world.getMoonPhase();

    const isNight = timeOfDay >= 12500 && timeOfDay <= 23500;

    if (isNight) {
      const sleepPercentage = moonPhase === 4 ? FULL_MOON_SLEEP_PERCENTAGE : NORMAL_SLEEP_PERCENTAGE;
      player.runCommand("/gamerule playerssleepingpercentage " + sleepPercentage.toString());
    }
  }

  handleMoonClock(player) {
    const equipment = player.getComponent("equippable");
    const selectedItem = equipment.getEquipment("Mainhand");
    if (!selectedItem || selectedItem.typeId !== "hb_hr:blood_moon_clock") return;

    const dimension = world.getDimension(player.dimension.id);
    if (dimension.id !== "minecraft:overworld") return;

    const timeOfDay = world.getTimeOfDay(); // 0 - 23999
    const moonPhase = world.getMoonPhase(); // 0 - 7
    const isNight = timeOfDay >= 12500 && timeOfDay <= 23500;

    // const sleepPercentage = moonPhase === 4 ? FULL_MOON_SLEEP_PERCENTAGE : NORMAL_SLEEP_PERCENTAGE;
    // player.runCommand(`/gamerule playerssleepingpercentage ${sleepPercentage}`);
    // world.sendMessage(`/gamerule playerssleepingpercentage ${sleepPercentage}`);

    // Moon phase name
    let moonPhaseText = "";
    switch (moonPhase) {
      case 0:
        moonPhaseText = "New Moon";
        break;
      case 1:
        moonPhaseText = "Waxing Crescent";
        break;
      case 2:
        moonPhaseText = "First Quarter";
        break;
      case 3:
        moonPhaseText = "Waxing Gibbous";
        break;
      case 4:
        moonPhaseText = "Full Moon";
        break;
      case 5:
        moonPhaseText = "Waning Gibbous";
        break;
      case 6:
        moonPhaseText = "Last Quarter";
        break;
      case 7:
        moonPhaseText = "Waning Crescent";
        break;
    }

    const daysUntilFullMoon = (4 - moonPhase + 8) % 8;
    const currentTime = timeOfDay;
    // Show final message on the night of the full moon
    if (moonPhase == 4 && currentTime >= 12500) {
      player.runCommand("/titleraw @s actionbar " + '{"rawtext":[{"translate":"hb_hr.red_moon_has_risen"}]}');
      return;
    }

    // Show anticipation message if full moon is today but hasn't started
    if (moonPhase == 4 && currentTime < 12500) {
      player.runCommand("/titleraw @s actionbar " + '{"rawtext":[{"translate":"hb_hr.red_moon_tonight"}]}');
      return;
    }

    // Show a countdown in full days only
    if (daysUntilFullMoon > 0) {
      // If exactly 1 day, use the singular key:
      if (daysUntilFullMoon == 1) {
        player.runCommand("/titleraw @s actionbar " + '{"rawtext":[' + '{"text":"1 "},' + '{"translate":"hb_hr.day_until_red_moon"}' + "]}");
      }
      // Otherwise (2+ days), use the plural key:
      else {
        player.runCommand("/titleraw @s actionbar " + '{"rawtext":[' + '{"text":"' + daysUntilFullMoon + ' "},' + '{"translate":"hb_hr.days_until_red_moon"}' + "]}");
      }
    }
  }

  spawnRandomMobAroundPlayer(player, mobType) {
    const dimension = player.dimension;
    const origin = player.location;
    const teleportRange = 20; // 10 in each direction = 20x20 area

    const offsetX = Math.floor(Math.random() * (teleportRange * 2 + 1)) - teleportRange;
    const offsetZ = Math.floor(Math.random() * (teleportRange * 2 + 1)) - teleportRange;

    const rayStart = {
      x: origin.x + offsetX,
      y: origin.y + 100, // high point
      z: origin.z + offsetZ,
    };

    const blockDetails = dimension.getBlockFromRay(
      rayStart,
      { x: 0, y: -1, z: 0 }, // look down
      { maxDistance: 300 }
    );

    if (blockDetails) {
      const ground = blockDetails.block.location;
      const spawnLocation = {
        x: ground.x + 0.5,
        y: ground.y + 1,
        z: ground.z + 0.5,
      };
      if (blockDetails.block.typeId != "minecraft:air") return;
      // world.sendMessage("spawned: " + mobType + " at: " + spawnLocation.x.toString());
      dimension.spawnEntity(mobType, spawnLocation);
    }
  }
  handleMoonDisplay(player, curTick) {
    const playerMoonTag = "hb_hr:" + player.id;
    let velocity = player.getVelocity();
    let loc = {
      x: player.location.x,
      y: player.location.y + (player.isSneaking ? 1.3 : 1.6),
      z: player.location.z,
    };
    const allMoons = player.dimension.getEntities({ type: "hb_hr:red_moon", tags: [playerMoonTag] });
    try {
      if (allMoons.length > 0) {
        allMoons.forEach((moon) => {
          if (!moon.isValid()) return;
          moon.teleport(loc);
          moon.applyImpulse(velocity);

          /*if (!moon.getComponent(EntityComponentTypes.Riding)) {
            const rideable = player.getComponent(EntityComponentTypes.Rideable);

            rideable?.ejectRiders();
            rideable?.addRider(moon);
          }*/
          moon.playAnimation("animation.hb_hr.red_moon.turn_on", { players: [player.name] });
          moon.addTag("moon_on");
        });
      } else {
        let newMoon = player.dimension.spawnEntity("hb_hr:red_moon", loc);
        newMoon.addTag(playerMoonTag);
      }
    } catch (error) {}
  }
}

export function isRedMoon() {
  const moonPhase = world.getMoonPhase();
  const timeOfDay = world.getTimeOfDay();
  const isNight = timeOfDay >= 12500 && timeOfDay <= 23500;
  if (isNight && moonPhase == 4) return true;
  else return false;
}

function getRandomSpawnLocationNearPlayer(player) {
  const dimension = player.dimension;
  const origin = player.location;
  const teleportRange = 20;

  const offsetX = Math.floor(Math.random() * (teleportRange * 2 + 1)) - teleportRange;
  const offsetZ = Math.floor(Math.random() * (teleportRange * 2 + 1)) - teleportRange;

  const rayStart = {
    x: origin.x + offsetX,
    y: origin.y + 100,
    z: origin.z + offsetZ,
  };

  const blockDetails = dimension.getBlockFromRay(rayStart, { x: 0, y: -1, z: 0 }, { maxDistance: 300 });

  if (blockDetails) {
    if (blockDetails.block.typeId == "minecraft:air") return "";
    const ground = blockDetails.block.location;
    return {
      x: ground.x + 0.5,
      y: ground.y + 1,
      z: ground.z + 0.5,
    };
  }

  return "";
}

/**
 * Returns how many game ticks until the next Red Moon starts
 * (night + full moon + time >= 12500)
 */
export function getTicksUntilNextRedMoon() {
  const timeOfDay = world.getTimeOfDay(); // 0–23999
  const moonPhase = world.getMoonPhase(); // 0–7

  // If it's already a red moon, return 0
  if (isRedMoon()) {
    return 0;
  }

  // How many full days until the next full moon (phase 4)?
  let daysUntilFullMoon = (FULL_MOON_PHASE - moonPhase + 8) % 8;

  // Already on a full moon day
  if (daysUntilFullMoon === 0) {
    if (timeOfDay < RED_MOON_START_TOD) {
      // Full moon happens today — wait until 12500
      return RED_MOON_START_TOD - timeOfDay;
    } else {
      // Full moon night already passed → next full moon in 8 days
      daysUntilFullMoon = 8;
    }
  }

  // Time until next full-moon day reaches morning (t=0)
  const ticksUntilNextFullMoonMorning =
    TICKS_PER_DAY -
    timeOfDay + // finish today's remainder
    (daysUntilFullMoon - 1) * TICKS_PER_DAY; // skip intermediate full days

  // Add the time from morning to 12500 (night start)
  return ticksUntilNextFullMoonMorning + RED_MOON_START_TOD;
}


