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

const CAPTURE_ITEMS = {
  "ph_wild:jar_empty": {
    sound: "bucket.fill_powder_snow",
    entities: {
      "ph_wild:butterfly": "ph_wild:jar_butterfly",
      "ph_wild:dragonfly": "ph_wild:jar_dragonfly",
      "ph_wild:hamster": "ph_wild:jar_hamster",
      "ph_wild:lizard": "ph_wild:jar_lizard",
      "ph_wild:snake": "ph_wild:jar_snake",
    }
  },
  "minecraft:water_bucket": {
    sound: "bucket.fill_fish",
    entities: {
      "ph_wild:jellyfish": "ph_wild:bucket_jellyfish",
      "ph_wild:octopus": "ph_wild:bucket_octopus",
    }
  }
};

const ITEM_EFFECTS = new Map([
  ["animal_fat", {
    effects: [
      { type: "nausea", duration: 500, amplifier: 0, probability: 0.1, particles: true }
    ]
  }],
  ["banana_peel", {
    effects: [
      { type: "nausea", duration: 300, amplifier: 0, probability: 1, particles: true }
    ]
  }],
  ["bucket_hippo_sweat", {
    effects: [
      { type: "fire_resistance", duration: 500, amplifier: 0, probability: 1, particles: true }
    ]
  }],
  ["potion_of_stingray_venom", {
    effects: [
      { type: "fatal_poison", duration: 400, amplifier: 3, probability: 1, particles: true },
      { type: "nausea", duration: 200, amplifier: 0, probability: 1, particles: false }
    ]
  }],
  ["potion_of_stingray_venom.lingering", {
    effects: [
      { type: "fatal_poison", duration: 200, amplifier: 3, probability: 1, particles: true },
      { type: "nausea", duration: 100, amplifier: 0, probability: 1, particles: false }
    ]
  }],
  ["shark_teeth_sword", {
    effects: [
      { type: "weakness", duration: 200, amplifier: 1, probability: 1, particles: true }
    ]
  }],
  ["strength_elixir", {
    effects: [
      { type: "strength", duration: 3600, amplifier: 3, probability: 1, particles: true },
      { type: "regeneration", duration: 800, amplifier: 1, probability: 0.1, particles: true }
    ]
  }],
  ["venomous_dagger", {
    effects: [
      { type: "fatal_poison", duration: 200, amplifier: 0, probability: 1, particles: true }
    ]
  }],
  ["venomous_stinger", {
    effects: [
      { type: "poison", duration: 40, amplifier: 0, probability: 1, particles: true }
    ]
  }],
]);

const EQUIPMENT_EFFECTS = new Map([
  ["ph_wild:tortoise_chestplate", {
    effects: [
      { type: "slowness", duration: 210, amplifier: 1, particles: false }
    ]
  }],
  ["ph_wild:claw_necklace", {
    effects: [
      { type: "speed", duration: 210, amplifier: 1, particles: false },
      { type: "strength", duration: 210, amplifier: 1, particles: false },
      { type: "hunger", duration: 210, amplifier: 0, particles: false },
      { type: "night_vision", duration: 210, amplifier: 0, particles: false },
      { type: "jump_boost", duration: 210, amplifier: 1, particles: false }
    ],
    durability: { chance: 5, damage: 8 }
  }],
]);

function showTempActionBar(player, message, duration = 20) {
  system.run(() => player.onScreenDisplay.setActionBar(message));
  system.runTimeout(() => player.onScreenDisplay.setActionBar(''), duration);
}

world.beforeEvents.playerInteractWithBlock.subscribe((event) => {
  const { block, blockFace, itemStack, player } = event;
  const spawnComponent = itemStack?.getComponent('ph_wild:spawn_entity');
  if (!spawnComponent) return;

  if (spawnComponent.customComponentParameters.params.block) {
    const placementDirections = {
      [Direction.Down]: block.below(),
      [Direction.Up]: block.above(),
      [Direction.North]: block.north(),
      [Direction.South]: block.south(),
      [Direction.East]: block.east(),
      [Direction.West]: block.west()
    };

    const placementLoc = block.isLiquid ? block.below(0) : placementDirections[blockFace];

    if (placementLoc && !placementLoc.isAir && !placementLoc.isLiquid) {
      showTempActionBar(player, '§4Invalid placement location');
      event.cancel = true;
      return;
    }
  }

  const itemData = itemStack.getDynamicProperty('ph_wild:item_data');
  if (itemData) {
    const { entityOwnerId } = JSON.parse(itemData);
    if (entityOwnerId && entityOwnerId !== player.id) {
      showTempActionBar(player, '§4Only the owner can place this entity');
      event.cancel = true;
    }
  }
});

system.beforeEvents.startup.subscribe(({ itemComponentRegistry }) => {
  itemComponentRegistry.registerCustomComponent("ph_wild:projectile", {
    onUse({ itemStack, source }, {params}) {
      const direction = source.getViewDirection();

      const right = {
        x: -direction.z,
        y: 0,
        z: direction.x,
      };

      const offset = { x: 0, y: 1.6, z: 0 };
      const angle = { pitch: 20, yaw: 0 };

      const pitchRad = (Math.PI / 180) * angle.pitch;
      const yawRad = (Math.PI / 180) * angle.yaw;

      const spawnLocation = {
        x: source.location.x + direction.x * offset.x + right.x * offset.z,
        y: source.location.y + offset.y,
        z: source.location.z + direction.z * offset.x + right.z * offset.z,
      };

      const adjustedDirection = {
        x: direction.x * Math.cos(yawRad) - direction.z * Math.sin(yawRad),
        y: direction.y + Math.sin(pitchRad),
        z: direction.x * Math.sin(yawRad) + direction.z * Math.cos(yawRad)
      };

      const magnitude = Math.sqrt(
        adjustedDirection.x ** 2 +
        adjustedDirection.y ** 2 +
        adjustedDirection.z ** 2
      );

      const velocity = {
        x: (adjustedDirection.x / magnitude) * params.speed,
        y: (adjustedDirection.y / magnitude) * params.speed,
        z: (adjustedDirection.z / magnitude) * params.speed
      };

      const projectile = source.dimension.spawnEntity(params.projectile, spawnLocation);

      const projectileData = {
        effects: ITEM_EFFECTS.get(params.effect).effects,
        hit_sound: params.hit_sound,
      };
      const storeStrData = JSON.stringify(projectileData);
      projectile.setDynamicProperty('ph_wild:projectile_data', storeStrData);

      source.dimension.playSound(params.launch_sound, source.location, { volume: 0.5, pitch: 0.5 });

      const projectileComp = projectile.getComponent('minecraft:projectile');
      projectileComp.shoot(velocity);
      if (projectileComp) {
        projectileComp.owner = source;
        projectileComp.gravity = -0.05;
        projectileComp.airInertia = 1;
      };
      if (params.replace_item && source.getGameMode() !== 'Creative') {
        const inv = source.getComponent("inventory").container;
        const slot = source.selectedSlotIndex;

        if (params.replace_item === 'consume') {
          if (itemStack.amount > 1) {
            itemStack.amount--;
            inv.setItem(slot, itemStack);
          } else {
            inv.setItem(slot, undefined);
          }
        } else {
          inv.setItem(slot, new ItemStack(params.replace_item));
        }
      }
    }
  });
  itemComponentRegistry.registerCustomComponent("ph_wild:consume", {
    onConsume({ itemStack, source }, { params }) {
      for (const { type, duration, amplifier, particles, probability } of ITEM_EFFECTS.get(params.effect).effects) {
        if (Math.random() <= probability) {
          source.addEffect(type, duration, {
            amplifier: amplifier,
            showParticles: particles,
          });
        }
      };
      if (params.replace_item && source.getGameMode() !== 'Creative') {
        const inv = source.getComponent("inventory").container;
        const slot = source.selectedSlotIndex;

        if (params.replace_item === 'consume') {
          if (itemStack.amount > 1) {
            itemStack.amount--;
            inv.setItem(slot, itemStack);
          } else {
            inv.setItem(slot, undefined);
          }
        } else {
          inv.setItem(slot, new ItemStack(params.replace_item));
        }
      }
    }
  });
  itemComponentRegistry.registerCustomComponent("ph_wild:attack", {
    onHitEntity({ hitEntity }, { params }) {
      for (const { type, duration, amplifier, particles, probability } of ITEM_EFFECTS.get(params.effect).effects) {
        if (Math.random() <= probability) {
          hitEntity.addEffect(type, duration, {
            amplifier: amplifier,
            showParticles: particles,
          });
        }
      };
    }
  });
  itemComponentRegistry.registerCustomComponent("ph_wild:spawn_entity", {
    onUseOn({ block, blockFace, itemStack, source }, { params }) {
      const faceOffsets = {
        [Direction.Up]: { x: 0, y: 0.5, z: 0 },
        [Direction.Down]: { x: 0, y: -1.5, z: 0 },
        [Direction.North]: { x: 0, y: 0, z: -1 },
        [Direction.South]: { x: 0, y: 0, z: 1 },
        [Direction.East]: { x: 1, y: 0, z: 0 },
        [Direction.West]: { x: -1, y: 0, z: 0 }
      };

      const offset = faceOffsets[blockFace] ?? { x: 0, y: 0, z: 0 };
      const spawnLocation = {
        x: block.center().x + offset.x,
        y: block.center().y + offset.y - (block.isLiquid ? 1 : 0),
        z: block.center().z + offset.z
      };

      const dx = source.location.x - spawnLocation.x;
      const dz = source.location.z - spawnLocation.z;
      const yaw = Math.atan2(dz, dx) * (180 / Math.PI) - 90;
      const entityRotation = { x: 0, y: yaw };

      const entity = source.dimension.spawnEntity(params.entity, spawnLocation);
      entity.setRotation(entityRotation);

      const itemData = itemStack.getDynamicProperty('ph_wild:item_data');
      if (itemData) {
        const {
          entityName,
          entityHealth,
          entityBaby,
          entityTamed,
          currentPage
        } = JSON.parse(itemData);

        if (entityName) entity.nameTag = entityName;
        if (entityHealth) entity.getComponent("health")?.setCurrentValue(entityHealth);
        entity.triggerEvent(entityBaby ? "baby" : "adult");
        if (entityTamed) entity.getComponent("tameable")?.tame(source);
        if (currentPage) entity.setProperty('ph_wild:current_page', currentPage);
      }

      const skinId = itemStack.typeId.match(/\d+$/)?.[0];
      if (skinId) entity.setProperty('ph_wild:skin', parseInt(skinId));

      if (params.block) {
        const placementMap = {
          [Direction.Down]: block.below(),
          [Direction.Up]: block.above(),
          [Direction.North]: block.north(),
          [Direction.South]: block.south(),
          [Direction.East]: block.east(),
          [Direction.West]: block.west()
        };

        const placementLoc = block.isLiquid ? block.below(0) : placementMap[blockFace];

        placementLoc?.setType(params.block);
      }

      if (params.sound) {
        block.dimension.playSound(params.sound, block.location);
      }

      if (params.replace_item && source.getGameMode() !== 'Creative') {
        const inv = source.getComponent("inventory").container;
        const slot = source.selectedSlotIndex;

        if (params.replace_item === 'consume') {
          if (itemStack.amount > 1) {
            itemStack.amount--;
            inv.setItem(slot, itemStack);
          } else {
            inv.setItem(slot, undefined);
          }
        } else {
          inv.setItem(slot, new ItemStack(params.replace_item));
        }
      }
    }
  });
  itemComponentRegistry.registerCustomComponent("ph_wild:maintain_durability", {
    onBeforeDurabilityDamage({ durabilityDamage }) {
        durabilityDamage -= 2;
      }
  });
});

const playerEquipmentState = new Map();

function updateEquipmentEffects() {
  for (const player of world.getAllPlayers()) {
    const currentState = new Set();
    const equipment = player.getComponent('equippable');

    if (!equipment) {
      playerEquipmentState.delete(player);
      continue;
    }

    for (const slot of ['Head', 'Chest', 'Legs', 'Feet', 'Offhand']) {
      const item = equipment.getEquipment(slot);
      if (!item?.typeId) continue;

      const effects = EQUIPMENT_EFFECTS.get(item.typeId);
      if (!effects) continue;

      for (const { type, duration, amplifier, particles } of effects.effects) {
        currentState.add(`${type}:${duration}:${amplifier}:${particles}`);
      };

      if (effects.durability) {
        const durabilityComp = item.getComponent('durability');
        const chance = ((Math.floor(Math.random() * 100) + 1) <= effects.durability.chance);
        if (chance > 0) {
          if ((durabilityComp.damage + effects.durability.damage) >= durabilityComp.maxDurability) {
            equipment.setEquipment(slot, undefined);
          } else {
            durabilityComp.damage += chance * effects.durability.damage; 
            equipment.setEquipment(slot, item);
            let time = 0;
            const stopsound = system.runInterval(() => {
              if (!player.isValid) {
                system.clearRun(stopsound);
                return;
              }
              if (time >= 5) {
                system.clearRun(stopsound);
              }
              player.runCommand(`/stopsound @s armor.equip_generic`);
              time += 1;
            }, 0);
          }
        }
      }
    }

    const previousState = playerEquipmentState.get(player) || new Set();

    for (const effectKey of previousState) {
      if (!currentState.has(effectKey)) {
        const [type] = effectKey.split(':');
        player.removeEffect(type);
      }
    }

    for (const effectKey of currentState) {
      const [type, duration, amplifier, particles] = effectKey.split(':');
      player.addEffect(type, parseInt(duration), {
        amplifier: parseInt(amplifier),
        showParticles: particles === 'true'
      });
    }

    playerEquipmentState.set(player, currentState);
  }
}

system.runInterval(updateEquipmentEffects, 5);


world.afterEvents.playerLeave.subscribe(({ player }) => {
  if (playerIntervals.has(player)) {
    system.clearRun(playerIntervals.get(player));
    playerIntervals.delete(player);
  }
  playerJumpState.delete(player);
  playerEquipmentState.delete(player);
});


//const loadedEntities = [];
//world.afterEvents.playerSpawn.subscribe(({ initialSpawn, player }) => {
//  if (initialSpawn) loadedEntities.push(player);
//});


const playerJumpState = new Map();
const playerIntervals = new Map();

world.afterEvents.playerButtonInput.subscribe(({ button, newButtonState, player }) => {
  if (button === 'Jump' && newButtonState === 'Pressed') {
    const equipment = player.getComponent('equippable');
    const item = equipment.getEquipment('Feet');

    if (item?.typeId !== 'ph_wild:winged_boots' || (player.isInWater || player.isSleeping || player.isClimbing || player.isGliding || player.isSneaking)) return;
    const gamemode = player.getGameMode();

    if (gamemode !== 'Adventure' && gamemode !== 'Survival') return;
    const durabilityComp = item.getComponent('durability');


    let jumpData = playerJumpState.get(player) || { state: 0, lastJump: 0 };
    const now = Date.now();

    if (jumpData.state === 1 && now - jumpData.lastJump > 250) {
      jumpData.state = 0;
      return;
    }

    if (jumpData.state === 0) {
      jumpData.state = 1;
      jumpData.lastJump = now;
      playerJumpState.set(player, jumpData);

      if (playerIntervals.has(player)) {
        system.clearRun(playerIntervals.get(player));
      }

      const intervalId = system.runInterval(() => {
        if (!player.isValid) {
          system.clearRun(intervalId);
          playerIntervals.delete(player);
          return;
        }

        if (player.isOnGround || player.isInWater || player.isSleeping || player.isClimbing || player.isGliding || player.isSneaking) {
          jumpData.state = 0;
          playerJumpState.set(player, jumpData);
          system.clearRun(intervalId);
          playerIntervals.delete(player);
        }
      }, 0);

      playerIntervals.set(player, intervalId);
    }
    else if (jumpData.state === 1) {
      if (durabilityComp.damage >= durabilityComp.maxDurability) {
        player.playSound('mob.camel.dash_ready', { location: player.location, volume: 0.25, pitch: 1.5 });
        return;
      }

      jumpData.state = 2;
      playerJumpState.set(player, jumpData);

      const viewDirection = player.getViewDirection();
      const moveVec = player.inputInfo.getMovementVector();

      const horizViewMag = Math.sqrt(viewDirection.x ** 2 + viewDirection.z ** 2);
      let forwardX = 0;
      let forwardZ = 1;

      if (horizViewMag > 1e-5) {
        forwardX = viewDirection.x / horizViewMag;
        forwardZ = viewDirection.z / horizViewMag;
      }

      const moveMag = Math.sqrt(moveVec.x ** 2 + moveVec.y ** 2);
      let moveX = 0;
      let moveZ = 0;

      if (moveMag > 1e-5) {
        moveX = moveVec.x / moveMag;
        moveZ = moveVec.y / moveMag;
      }

      const rightX = forwardZ;
      const rightZ = -forwardX;

      let worldX = moveX * rightX + moveZ * forwardX;
      let worldZ = moveX * rightZ + moveZ * forwardZ;

      const mag = Math.sqrt(worldX ** 2 + worldZ ** 2);
      if (mag > 1e-5) {
        worldX /= mag;
        worldZ /= mag;
      } else {
        worldX = forwardX;
        worldZ = forwardZ;
      }

      player.applyKnockback({ x: worldX * 3.0, z: worldZ * 3.0 }, 1.0);

      player.playSound('ph_wild.winged_boots.dash', { location: player.location, volume: 1, pitch: 0.8 });

      let random = Math.random() * 1e3;

      player.startItemCooldown(`ph_wild_winged_boots_anim`, 15);

      player.playAnimation("animation.ph_wild.player.winged_boots", {
        controller: "controller.animation.ph_wild.player.winged_boots",
        stopExpression: `
        v.ph_wild_player_rotation_x = ${moveX};
        v.ph_wild_player_rotation_z = ${moveZ};
        v.ph_wild_random_reset = ${random};
        return q.all_animations_finished || q.is_sneaking || q.blocking;`
      });

      durabilityComp.damage += 1;
      equipment.setEquipment('Feet', item);

      let time = 0;
      const stopsound = system.runInterval(() => {
        if (!player.isValid) {
          system.clearRun(stopsound);
          return;
        }
        if (time >= 5) {
          system.clearRun(stopsound);
        }

        player.runCommand(`/stopsound @s armor.equip_leather`);
        player.runCommand(`/stopsound @s armor.equip_generic`);
        time += 1;
      }, 0);
    }
  }
});

world.afterEvents.playerInteractWithEntity.subscribe(({ itemStack, player, target }) => {
  if (!itemStack) return;

  const captureData = CAPTURE_ITEMS[itemStack.typeId];
  const targetId = target.typeId;
  const newItemId = captureData?.entities[targetId];

  if (!newItemId) return;

  const health = target.getComponent("health");
  const skinId = target.getProperty("ph_wild:skin") || "default";
  const isBaby = target.hasComponent("minecraft:is_baby");
  const tameable = target.getComponent("tameable");

  const capturedItem = new ItemStack(`${newItemId}_${skinId}`);

  capturedItem.setDynamicProperty("ph_wild:item_data", JSON.stringify({
    entityName: target.nameTag,
    entityHealth: health?.currentValue,
    entityBaby: isBaby,
    entityTamed: tameable?.isTamed,
    entityOwnerId: tameable?.tamedToPlayerId
  }));

  const lore = [
    `§r§7Name: ${target.nameTag || "Unknown"}`,
    `§r§7Health: ${health?.currentValue}/${health?.defaultValue}`,
    `§r§7Age: ${isBaby ? "Baby" : "Adult"}`
  ];

  if (tameable?.tamedToPlayer?.nameTag) {
    lore.push(`§r§7Owner: ${tameable.tamedToPlayer.nameTag}`);
  }

  capturedItem.setLore(lore);

  const inventory = player.getComponent("inventory").container;
  const slot = player.selectedSlotIndex;

  if (player.getGameMode() !== "Creative") {
    itemStack.amount > 1
      ? (itemStack.amount--, inventory.setItem(slot, itemStack))
      : inventory.setItem(slot);
  }

  inventory.addItem(capturedItem);

  target.dimension.playSound(captureData.sound, target.location);
  target.remove();
});