import { BlockPermutation, BlockVolume, EntityProjectileComponent, EquipmentSlot, GameMode, HudElement, ItemStack, MolangVariableMap, Player, system, world } from '@minecraft/server'
import { dynamicWeaponsConfig } from './weapons.config';
import { getRelative, shootCommon, applyCircleImpulse, applyImpulseTowardsLocation, sphereCoordinates, getRandomXYZ, getRelative2 } from '../UTILS/globalVars';
import { Vec3 } from '../UTILS/Vec3';

export const dwInjections = new Map();
const dwICache = {};

dwInjections.set("dive_hw:hacker_sword", {
    hasCooldown: true,
    attacks: [
    {
      testCooldown: false,
      injectorType: "onHit",
      toInject: (damagingEntity, hitEntity) => {
        function checkProbability(prob) {
        return Math.random() < prob;
      }
      if (!damagingEntity || !hitEntity || hitEntity.id === damagingEntity.id) return;

      const {
        hacker_sword: {
          normal: { probability, durationHacking, effectsToAdd, range }
        }
      } = dynamicWeaponsConfig;

      if (!checkProbability(probability)) return;

      const entities = damagingEntity.dimension
        .getEntities({
          location: damagingEntity.location,
          maxDistance: range,
          excludeFamilies: ["inanimate"]
        })
        .filter(e => e.id !== damagingEntity.id);

      const lagMap = new WeakMap();

      // HACKEO DE MOVIMIENTO
      const hackMovement = system.runInterval(() => {
        for (const entity of entities) {
          try {
            const prevLoc = lagMap.get(entity) || entity.location;
            entity.teleport(prevLoc);
            lagMap.set(entity, entity.location);
          } catch {}
        }
      }, 8);

      // PARTICULAS CADA N SEGUNDOS (ej: 20 ticks = 1 seg)
      const particleInterval = 25; // Puedes hacer esto configurable si quieres
      const particleTicker = system.runInterval(() => {
        for (const entity of entities) {
          try {
            entity.dimension.spawnParticle("dive_hw:glitch_particle", entity.location);
          } catch {}
        }
      }, particleInterval);

      // DETENER LOS INTERVALOS DESPUÉS DE DURACIÓN
      system.runTimeout(() => {
        system.clearRun(hackMovement);
        system.clearRun(particleTicker);
      }, durationHacking * 20);

      // APLICAR EFECTOS
      for (const entity of entities) {
        for (const [name, duration, amplifier, prob, showParticles] of effectsToAdd) {
          if (!checkProbability(prob)) continue;
          entity.addEffect(name, duration, { amplifier, showParticles });
        }
      }
    }
    },
    {
        testCooldown: true,
        injectorType: "onUse",
        toInject: (source) => {
            const { hacker_sword: { special: { range, particle, damagePerSecond, durationHacking, effectsToAdd } } } = dynamicWeaponsConfig;
            const entities = source.dimension.getEntities({ location: source.location, maxDistance: range, minDistance: 0 }).filter(entity => entity.id !== source.id);
            const inject = system.runInterval(() => {
                for (const entity of entities) {
                    try {

                    entity.applyDamage(damagePerSecond);
                    } catch (error) { }
                }
            }, 5);
            system.runTimeout(() => system.clearRun(inject), durationHacking * 20);
            for (const [name, duration, amplifier, probability, showParticles] of effectsToAdd) {
            if (!probability.checkProbability) continue;
            try {
                entities.forEach(e => {e.addEffect(name, duration, { amplifier, showParticles }); e.dimension.spawnParticle("dive_hw:glitch_particle", e.location);});
            } catch (error) { }
            }
            return;
        }
        }
    ]
});
dwInjections.set("dive_hw:hacker_blade", {
    hasCooldown: true,
    attacks: [
        {
        testCooldown: false,
        injectorType: "onHit", //Basic attack
        toInject: (damagingEntity, hitEntity) => {
            const { hacker_blade: { normal: { probability, entity_effect, durationHacking, effectsToAdd, particle, maxDistance } } } = dynamicWeaponsConfig;
            if (!probability.checkProbability) return;
            const rel = getRelative(damagingEntity, damagingEntity.getViewDirection(), [1.5, 1.5, 0]);
            const pro = damagingEntity.dimension.spawnEntity(entity_effect, rel);
            const lag = new WeakMap();
            const rot = damagingEntity.getRotation();
            pro.setProperty("dive_hw:rotation_x", rot.x);
            pro.setProperty("dive_hw:rotation_y", rot.y);
            dwICache.excludes.add(damagingEntity.id);
            dwICache.excludes.add(pro.id);
            const entities = damagingEntity.dimension.getEntities({ location: damagingEntity.location, minDistance: 0, maxDistance }).filter(({ id }) => !dwICache.excludes.has(id));
            const inject = system.runInterval(() => {
            for (const entity of entities) {
                try {
                entity.teleport(lag.has(entity) ? lag.get(entity) : entity.location);
                lag.set(entity, entity.location);
                } catch (error) {
                continue;
                }
            }
            }, 8);
            system.runTimeout(() => system.clearRun(inject), durationHacking * 20);
            for (const entity of entities) {
            for (const [name, duration, amplifier, probability, showParticles] of effectsToAdd) {
                if (!probability.checkProbability) continue;
                entity.addEffect(name, duration, { amplifier, showParticles });
            }
            }
            dwICache.excludes.delete(damagingEntity.id);
            dwICache.excludes.delete(pro.id);
            return;
        }
        },
        {
        testCooldown: true,
        injectorType: "onUse", //Speacial attack
        toInject: (source) => {
            const { hacker_blade: { special: { range, overloadDamage, durationHacking, particle, overloadParticle, effectsToAdd } } } = dynamicWeaponsConfig;
            const entities = source.dimension.getEntities({ location: source.location, maxDistance: range, excludeFamilies: ["npc"]}).filter(entity => entity.id !== source.id);
            source.dimension.spawnParticle(particle, source.getHeadLocation());
            const inject = system.runInterval(() => {
            for (const entity of entities) {
                try {
                entity.teleport(entity.location);
                entity.applyDamage(1);
                } catch (error) { }
            }
            });
            system.runTimeout(() => {
            system.clearRun(inject);
            entities.forEach(e => {
                try {
                e.applyDamage(overloadDamage);
                e.dimension.spawnParticle(overloadParticle, e.getHeadLocation());
                e.dimension.spawnParticle(overloadParticle, e.getHeadLocation());
                } catch (error) { }
            });
            }, durationHacking * 20);
            for (const [name, duration, amplifier, probability, showParticles] of effectsToAdd) {
            if (!probability.checkProbability) continue;
            try {
                entities.forEach(e => e.addEffect(name, duration, { amplifier, showParticles }));
            } catch (error) { }
            }
            return;
        }
        }
    ]
});
dwInjections.set("dive_hw:hacker_blade_slash_particle", {
  hasCooldown: false,
  destroyAtFinished: true,
  attacks: [
    {
      testCooldown: false,
      injectorType: "onHitByProjectile",
      toInject: (projectile, hitEntity, source) => {
        if (!hitEntity || !source || hitEntity.id === source.id) return;
        const {
          hacker_blade: {
            projectileHit: { effectsToAdd, particle }
          }
        } = dynamicWeaponsConfig;
        hitEntity.dimension.spawnParticle(particle, hitEntity.location);
        for (const [name, duration, amplifier, probability, showParticles] of effectsToAdd) {
          if (Math.random() < probability) {
            hitEntity.addEffect(name, duration, { amplifier, showParticles });
            hitEntity.applyDamage(6);
          }
        }
      }
    }
  ]
});

dwInjections.set("dive_hw:hacker_axe", {
  hasCooldown: true,
  attacks: [
    {
      testCooldown: false,
      injectorType: "onHit",
      toInject: (damagingEntity, hitEntity) => {
        const {
          hacker_axe: {
            normal: { overloadParticle, entity_effect, durationHacking, effectsToAdd }
          }
        } = dynamicWeaponsConfig;

        if (!damagingEntity || !hitEntity || hitEntity.id === damagingEntity.id) return;

        const rel = getRelative(damagingEntity, damagingEntity.getViewDirection(), [1, 1, 0]);
        const pro = damagingEntity.dimension.spawnEntity(entity_effect, rel);

        const rot = damagingEntity.getRotation();
        pro.setProperty("dive_hw:rotation_x", rot.x);
        pro.setProperty("dive_hw:rotation_y", rot.y);

        const lag = new WeakMap();

        const inject = system.runInterval(() => {
          try {
            hitEntity.teleport(lag.get(hitEntity) || hitEntity.location);
            lag.set(hitEntity, hitEntity.location);
          } catch {}
        }, 4);

        system.runTimeout(() => {
          system.clearRun(inject);
          if(!hitEntity.isValid()) return;
          hitEntity?.dimension.spawnParticle(overloadParticle, hitEntity.getHeadLocation());
        }, durationHacking * 20);

        for (const [name, duration, amplifier, probability, showParticles] of effectsToAdd) {
          if (Math.random() < probability) {
            hitEntity.addEffect(name, duration, { amplifier, showParticles });
          }
        }
      }
    },
        {
        testCooldown: true,
        injectorType: "onUse",
        toInject: (source) => {
            const { hacker_axe: { special: { range, rangeDamage, particle, overloadParticle, cooldownToKick, effectsToAdd } } } = dynamicWeaponsConfig;
            const entities = source.dimension.getEntities({ location: source.location, maxDistance: range, minDistance: 0, excludeFamilies: ["npc"] }).filter(entity => entity.id !== source.id);

            for (const [name, duration, amplifier, probability, showParticles] of effectsToAdd) {
            if (!probability.checkProbability) continue;

            entities.forEach(e => {
                e.addEffect(name, duration, { amplifier, showParticles });
            });
            }
            system.runTimeout(() => {
            source.dimension.spawnParticle(particle, source.getHeadLocation());
            entities.forEach(e => {
                try {
                e.applyDamage(rangeDamage);
                e.dimension.spawnParticle(overloadParticle, e.getHeadLocation());
                e.dimension.spawnParticle(overloadParticle, e.getHeadLocation());
                e.setOnFire(3);
                applyCircleImpulse(e, source.location);
                } catch (error) { }
            });
            }, cooldownToKick * 20);
            return;
        }
        }
    ]
});
dwInjections.set("dive_hw:hacker_bow_projectile", {
  hasCooldown: false,
  destroyAtFinished: true,
  attacks: [
    {
      testCooldown: false,
      injectorType: "onHitByProjectile",
      toInject: (projectile, hitEntity, source) => {
        let isSpecial = projectile.getProperty("dive_hw:special");
        const {
          normal: { damage, particle, overloadParticle },
          special: { rainRange, high, maxArrows, centerParticle }
        } = dynamicWeaponsConfig.hacker_bow;
        projectile.remove();
        
        const headLoc = hitEntity.getHeadLocation();
        hitEntity.dimension.spawnParticle(particle, headLoc);
        const rand = Math.random();
        let appliedEffect = false;
        if (!isSpecial) {
          if (rand < 0.5) {
            const effect = Math.random() < 0.5 ? "nausea" : "blindness";
            hitEntity.addEffect(effect, 60, { amplifier: 0, showParticles: true });
            appliedEffect = true;
          }
          if (rand < 0.7) {
            hitEntity.addEffect("weakness", 80, { amplifier: 0, showParticles: true });
            appliedEffect = true;
          }
          if (!appliedEffect) {
            hitEntity.dimension.spawnParticle(overloadParticle, headLoc);
          }
          system.runTimeout(() => {
            hitEntity.applyDamage(damage);
          }, 10);
        }
        //Codebreaker Volley ===
        else {
          if (source.hasTag("codebreaker_cooldown")) return;
          source.addTag("codebreaker_cooldown");
          system.runTimeout(() => {
            if (source?.isValid()) source.removeTag("codebreaker_cooldown");
          }, 20 * 20); // 20s cooldown
          const center = {
            x: hitEntity.location.x,
            y: hitEntity.location.y + high,
            z: hitEntity.location.z
          };
          hitEntity.dimension.spawnParticle(centerParticle, center);
          for (let i = 0; i < maxArrows; i++) {
            const angle = Math.random() * Math.PI * 2;
            const dist = Math.sqrt(Math.random()) * rainRange;
            const x = center.x + Math.cos(angle) * dist;
            const z = center.z + Math.sin(angle) * dist;
            const y = center.y;
            const arrow = hitEntity.dimension.spawnEntity("minecraft:arrow", { x, y, z });
          }
          const affected = hitEntity.dimension.getEntities({
            location: hitEntity.location,
            maxDistance: rainRange,
            excludeFamilies: ["inanimate"]
          });
          for (const entity of affected) {
            if (entity.id === source.id) continue;
            entity.addEffect("slowness", 60, { amplifier: 1 });
            entity.addEffect("weakness", 60, { amplifier: 1 });
            entity.addEffect("mining_fatigue", 60, { amplifier: 1 });
          }
        }
      }
    }
  ]
});
dwInjections.set("dive_hw:hacker_crossbow_projectile", {
  hasCooldown: false,
  destroyAtFinished: true,
  attacks: [
    {
      testCooldown: false,
      injectorType: "onHitByProjectile",
      toInject: (projectile, hitEntity, source) => {
        const isSpecial = projectile.getProperty("dive_hw:special");
        const {
          normal: { damage, particle, overloadParticle },
          special: {
            rainRange, high, maxArrows, centerParticle,
            capDistance
          }
        } = dynamicWeaponsConfig.hacker_crossbow;
        projectile.remove();
        hitEntity.dimension.spawnParticle(particle, hitEntity.location);
        // === Normal Attack ===
        if (!isSpecial) {
          let disrupted = false;
          const positiveEffects = ["speed", "jump_boost", "regeneration", "absorption"];
          for (const effect of positiveEffects) {
            if (hitEntity.getEffect(effect)) {
              hitEntity.removeEffect(effect);
              disrupted = true;
            }
          }
          if (Math.random() < 0.7) {
            hitEntity.addEffect("weakness", 80, { amplifier: 0, showParticles: true });
            disrupted = true;
          }
          if (!disrupted) {
            hitEntity.dimension.spawnParticle(overloadParticle, hitEntity.getHeadLocation());
          }
          system.runTimeout(() => {
            hitEntity.applyDamage(damage);
          }, 10);
        }
        // === Special Attack: Network Snare ===
        else {
          if (source.hasTag("network_snare_cd")) return;
          source.addTag("network_snare_cd");
          system.runTimeout(() => {
            if (source?.isValid()) source.removeTag("network_snare_cd");
          }, 20 * 20); // 20s cooldown
          const relCenter = {
            x: hitEntity.location.x,
            y: hitEntity.location.y + high,
            z: hitEntity.location.z
          };
          hitEntity.dimension.spawnParticle(centerParticle, relCenter);
          const affected = hitEntity.dimension.getEntities({
            location: hitEntity.location,
            minDistance: 0,
            maxDistance: capDistance,
            excludeFamilies: ["inanimate"]
          });
          for (const entity of affected) {
            if (entity.id === source.id) continue;
            entity.dimension.spawnParticle(centerParticle, relCenter);
            entity.addEffect("slowness", 100, { amplifier: 1 }); // 5s
            entity.addEffect("mining_fatigue", 100, { amplifier: 1 }); // -20% atk speed
          }

          system.runTimeout(() => {
            hitEntity.dimension.spawnParticle(centerParticle, hitEntity.location);
          }, 20);
        }
      }
    }
  ]
});
dwInjections.set("dive_hw:hacker_hammer", {
  hasCooldown: true,
  attacks: [
    {
      testCooldown: false,
      injectorType: "onHit",
      toInject: (damagingEntity, hitEntity) => {
        const { hacker_hammer: { normal: { probability, entity_effect, durationHacking, effectsToAdd } } } = dynamicWeaponsConfig;
        if (!probability.checkProbability) return;

        const rel = getRelative(damagingEntity, damagingEntity.getViewDirection(), [1, 1, 0]);
        const pro = damagingEntity.dimension.spawnEntity(entity_effect, rel);
        const lag = new WeakMap();
        const rot = damagingEntity.getRotation();
        pro.setProperty("dive_hw:rotation_x", rot.x);
        pro.setProperty("dive_hw:rotation_y", rot.y);

        const inject = system.runInterval(() => {
          try {
            hitEntity.teleport(lag.get(hitEntity) || hitEntity.location);
            lag.set(hitEntity, hitEntity.location);
          } catch (error) { }
        }, 8);
        system.runTimeout(() => system.clearRun(inject), durationHacking * 20);
        for (const [name, duration, amplifier, probability, showParticles] of effectsToAdd) {
          if (!probability.checkProbability) continue;

          hitEntity.addEffect(name, duration, { amplifier, showParticles });

          hitEntity.dimension.spawnParticle("dive_hw:hammer_particle", hitEntity.location)
        }
        return;
      }
    },
    {
      testCooldown: true,
      injectorType: "onUse",
      toInject: (source) => {
        const { hacker_hammer: { special: { range, damagePerSecond, particle, overloadParticle, durationHacking, cooldownToImpact, effectsToAdd } } } = dynamicWeaponsConfig;

        system.runTimeout(async () => {
          const entities = source.dimension.getEntities({ location: source.location, maxDistance: range, minDistance: 0 }).filter(entity => entity.id !== source.id);

          const relP = getRelative(source, source.getViewDirection(), [2, 0, 0], source.location.y);
          source.dimension.spawnParticle(particle, source.location);
          entities.forEach(e => {
            try {
              e.dimension.spawnParticle("dive_hw:hammer_particle", e.location)
              applyCircleImpulse(e, source.location);
            } catch (error) { }
          });

          await new Promise(resolve => system.runTimeout(resolve, 2));
          const inject = system.runInterval(() => {
            for (const entity of entities) {
              try {
                entity.applyDamage(damagePerSecond);
              } catch (error) { }
            }
          }, 10);
          system.runTimeout(() => {
            system.clearRun(inject);
            entities.forEach(e => {
              try {
                e.setOnFire(3)
              } catch (error) { }
            });
          }, durationHacking * 20);
          for (const [name, duration, amplifier, probability, showParticles] of effectsToAdd) {
            if (!probability.checkProbability) continue;

            try {
              entities.forEach(e => e.addEffect(name, duration, { amplifier, showParticles }));
            } catch (error) { }
          }
        }, cooldownToImpact * 20);
        return;
      }
    }
  ]
});
dwInjections.set("dive_hw:hacker_blaster", {
  hasCooldown: true,
  attacks: [
    {
      testCooldown: true,
      injectorType: "onUse",
      toInject: (source) => {
        const { 
          hacker_blaster: {
            secondsToShoot, 
            normal: { particle, damage, overloadParticle, effectsToAdd }
          }
        } = dynamicWeaponsConfig;

        const viewDir = source.getViewDirection();
        const step = 0.4;
        const amount = 50;
        const startOffset = 1.0;
        const hitRadius = 1.25; // Precisión del rayo
        const hitEntities = new Set();

        system.runTimeout(() => {
          for (let i = 0; i < amount; i++) {
             const distance = startOffset + i * step;
            const offsetX = viewDir.x * distance;
            const offsetY = viewDir.y * distance;
            const offsetZ = viewDir.z * distance;
            const location = {
                x: source.location.x + offsetX,
                y: source.location.y + offsetY,
                z: source.location.z + offsetZ
            };
            const map = new MolangVariableMap();
            map.setFloat("variable.x", viewDir.x);
            map.setFloat("variable.y", viewDir.y);
            map.setFloat("variable.z", viewDir.z);
            source.dimension.spawnParticle("dive_hw:laser_beam_1_core", location, map);
            const nearbyEntities = source.dimension.getEntities({
              location,
              maxDistance: hitRadius
            }).filter(e => 
              e.id !== source.id && 
              !hitEntities.has(e.id) &&
              e.isValid()
            );
            for (const target of nearbyEntities) {
              hitEntities.add(target.id);
              target.applyDamage(damage);
              for (const [name, duration, amplifier, probability, showParticles] of effectsToAdd) {
                if (!probability.checkProbability) continue;
                target.addEffect(name, duration, { amplifier, showParticles });
              }
            }
          }
        }, secondsToShoot * 20);
      }
    }
  ]
});

dwInjections.set("dive_hw:hacker_laser", {
  hasCooldown: true,
  attacks: [
    {
      testCooldown: true,
      injectorType: "onUse",
      toInject: (source) => {
        const { hacker_laser: { secondsToShoot, secondsToRemoveProjectile, normal: { particle } } } = dynamicWeaponsConfig;
        system.runTimeout(async () => {
          for (let i = 0; i < 3; i++) {
            const rel = getRelative(source, source.getViewDirection(), [1.3, 1, 0]);
            const rot = source.getRotation();
            const pro = source.dimension.spawnEntity("dive_hw:hacker_laser_projectile", rel);
            pro.setProperty("dive_hw:rotation_x", rot.x);
            pro.setProperty("dive_hw:rotation_y", rot.y);
            pro.setProperty("dive_hw:special", source.isSneaking);
            const proyectil = pro.getComponent(EntityProjectileComponent.componentId);
            const vw = source.getViewDirection();
            proyectil.shoot({
              x: (vw.x * 2),
              y: vw.y,
              z: (vw.z * 2)
            });
            proyectil.owner = source;
            system.runTimeout(() => {
              try {
                pro.remove();
              } catch (error) { }
            }, secondsToRemoveProjectile * 20);
            await new Promise(resolve => system.runTimeout(resolve, 6));
          }
        }, secondsToShoot * 20);
      }
    }
  ]
});
dwInjections.set("dive_hw:hacker_laser_projectile", {
  hasCooldown: false,
  destroyAtFinished: true,
  attacks: [
    {
      testCooldown: false,
      injectorType: "onHitByProjectile",
      toInject: (projectile, hitEntity, source) => {
        const { normal: { damage, overloadParticle, effectsToAdd } } = dynamicWeaponsConfig.hacker_laser;

        hitEntity.applyDamage(damage);
        hitEntity.dimension.spawnParticle("dive_hw:glitch_particle", hitEntity.getHeadLocation());
        for (const [name, duration, amplifier, probability, showParticles] of effectsToAdd) {
          if (!probability.checkProbability) continue;

          hitEntity.addEffect(name, duration, { amplifier, showParticles });
        }
        return;
      }
    }
  ]
});

dwInjections.set("dive_hw:hacker_chopper", {
  hasCooldown: true,
  attacks: [
    {
      testCooldown: true,
      injectorType: "onUse",
      toInject: (source) => {
        const { hacker_chopper: { secondsToStart, entity_effect } } = dynamicWeaponsConfig;

        system.runTimeout(async () => {
          const startBlock = source.getBlockFromViewDirection()?.block;
          if (!startBlock) return;
          const Id = startBlock.typeId;

          if (!startBlock || !Id.includes("log")) return;

          await system.waitTicks(10);
          let count = 0;
          const queue = [startBlock.location];
          const checked = new Set();
          const directions = [
            { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 },
            { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 },
            { x: 0, y: 1, z: 0 }, { x: 0, y: -1, z: 0 },
            { x: 1, y: 1, z: 0 }, { x: -1, y: 1, z: 0 },
            { x: 0, y: 1, z: 1 }, { x: 0, y: 1, z: -1 },
            { x: 1, y: -1, z: 0 }, { x: -1, y: -1, z: 0 },
            { x: 0, y: -1, z: 1 }, { x: 0, y: -1, z: -1 }
          ];

          while (queue.length > 0) {
            const { x, y, z } = queue.shift();
            const locKey = `${x},${y},${z}`;

            if (checked.has(locKey)) continue;
            checked.add(locKey);

            const block = source.dimension.getBlock({ x, y, z });
            
            if (block && block.typeId.includes("log")) {
              block.dimension.spawnParticle("dive_hw:scan", block.location)
              system.runTimeout(() => {
                source.dimension.setBlockPermutation({ x, y, z }, BlockPermutation.resolve("minecraft:air"));
              }, 40)
              count++;

              for (const dir of directions) {
                const newX = x + dir.x;
                const newY = y + dir.y;
                const newZ = z + dir.z;

                const newLocKey = `${newX},${newY},${newZ}`;
                if (!checked.has(newLocKey)) {
                  queue.push({ x: newX, y: newY, z: newZ });
                }
              }
            }
          }
          system.runTimeout(() => {
            const items = new ItemStack(Id, count);
          source.dimension.spawnItem(items, startBlock.location);
          source.playSound("random.pop2");
          }, 40)
          
        }, secondsToStart * 20);
      }
    }
  ]
});
dwInjections.set("dive_hw:hacker_pickaxe", {
  hasCooldown: true,
  attacks: [
      {
          testCooldown: true,
          injectorType: "onUse",
          toInject: (source) => {
              const { hacker_pickaxe: { particle } } = dynamicWeaponsConfig;

              const direction = source.getViewDirection();
              let facing = "";
              if (Math.abs(direction.x) > Math.abs(direction.z)) {
                  facing = direction.x > 0 ? "east" : "west";
              } else {
                  facing = direction.z > 0 ? "south" : "north";
              }
              const startX = Math.floor(source.location.x);
              const startY = Math.floor(source.location.y);
              const startZ = Math.floor(source.location.z);
              let minX, minY, minZ, maxX, maxY, maxZ;
              if (facing === "north" || facing === "south") {
                  minX = startX - 1;
                  maxX = startX + 1;
                  minZ = facing === "north" ? startZ - 2 : startZ + 1;
                  maxZ = facing === "north" ? startZ : startZ + 2;
              } else {
                  minZ = startZ - 1;
                  maxZ = startZ + 1;
                  minX = facing === "west" ? startX - 2 : startX + 1;
                  maxX = facing === "west" ? startX : startX + 2;
              }

              minY = startY;
              maxY = startY + 2; // Rango de altura 3 bloques

              // 📌 Ejecutar el comando /fill para romper los bloques con loot
              source.runCommand(`fill ${minX} ${minY} ${minZ} ${maxX} ${maxY} ${maxZ} air destroy`);

              // 📌 Efectos visuales
              for (let x = minX; x <= maxX; x++) {
                  for (let y = minY; y <= maxY; y++) {
                      for (let z = minZ; z <= maxZ; z++) {
                          source.dimension.spawnParticle(particle, { x, y, z });
                      }
                  }
              }
          }
      }
  ]
});
dwInjections.set("dive_hw:hacker_drill", {
  hasCooldown: true,
  attacks: [
    {
      testCooldown: true,
      injectorType: "onUse",
      toInject: (source) => {
        const {
          hacker_drill: { ticksToStart, duration, rangeMiner, particle }
        } = dynamicWeaponsConfig;
        const direction = source.getViewDirection();
        const startX = Math.floor(source.location.x);
        const startY = Math.floor(source.location.y);
        const startZ = Math.floor(source.location.z);
        let facing = "";
        let verticalMode = false;
        if (direction.y < -0.7) {
          verticalMode = true;
        } else {
          if (Math.abs(direction.x) > Math.abs(direction.z)) {
            facing = direction.x > 0 ? "east" : "west";
          } else {
            facing = direction.z > 0 ? "south" : "north";
          }
        }
        let step = 0;
        system.runTimeout(() => {
          const repeat = system.runInterval(() => {
            let minX, maxX, minY, maxY, minZ, maxZ;
            let centerParticle = { x: 0, y: 0, z: 0 };
            if (verticalMode) {minX = startX - 1;maxX = startX + 1;minZ = startZ - 1;maxZ = startZ + 1;minY = startY - step - 2;maxY = startY - step;
              centerParticle = {
                x: startX,
                y: minY + 1,
                z: startZ
              };
            } else {
              if (facing === "north" || facing === "south") {
                minX = startX - 1;
                maxX = startX + 1;
                minZ = facing === "north" ? startZ - step - 2 : startZ + step + 1;
                maxZ = facing === "north" ? startZ - step : startZ + step + 3;
                centerParticle = {
                  x: startX,
                  y: startY + 1,
                  z: (minZ + maxZ) / 2
                };
              } else {
                minZ = startZ - 1;
                maxZ = startZ + 1;
                minX = facing === "west" ? startX - step - 2 : startX + step + 1;
                maxX = facing === "west" ? startX - step : startX + step + 3;
                centerParticle = {
                  x: (minX + maxX) / 2,
                  y: startY + 1,
                  z: startZ
                };
              }
              minY = startY;
              maxY = startY + 2;
            }
            source.runCommandAsync(
              `fill ${minX} ${minY} ${minZ} ${maxX} ${maxY} ${maxZ} air destroy`
            );
            source.dimension.spawnParticle(particle, centerParticle);
            step++;
          }, 10);
          system.runTimeout(() => system.clearRun(repeat), duration * 20);
        }, ticksToStart);
      }
    }
  ]
});
dwInjections.set("dive_hw:hacker_hoe", {
  hasCooldown: true,
  attacks: [
    {
      testCooldown: false,
      injectorType: "onUse",
      toInject: (source) => {
        const { hacker_hoe: { secondsToStart } } = dynamicWeaponsConfig;
        const viewBlock = source.getBlockFromViewDirection()?.block;
        if (!viewBlock) return;
        const dis = Vec3.distance(source.location, viewBlock.location);
        if (dis > 5) return;
        const val = new Set([
          "minecraft:dirt", 
          "minecraft:grass_block", 
          "minecraft:dirt_with_roots", 
          "minecraft:coarse_dirt"
        ]);
        if (val.has(viewBlock.typeId)) {
          system.runTimeout(() => {
            viewBlock.dimension.spawnParticle("dive_hw:hoe_particle", {
              x: viewBlock.location.x, 
              y: viewBlock.location.y + 1, 
              z: viewBlock.location.z
            });
            viewBlock.setPermutation(BlockPermutation.resolve("minecraft:farmland"));
          }, secondsToStart * 20);
          return;
        }
        if (source.isSneaking) {
          const block = viewBlock;
          const ID = block.typeId;
          const crops = {
            "minecraft:wheat": { max: 7, drop: "wheat", seeds: "wheat_seeds", min: 1, max: 3 },
            "minecraft:carrots": { max: 7, drop: "carrot", min: 2, max: 5 },
            "minecraft:potatoes": { max: 7, drop: "potato", min: 1, max: 4 },
            "minecraft:beetroot": { max: 7, drop: "beetroot", seeds: "beetroot_seeds", min: 1, max: 2 },
            "minecraft:pitcher_crop": { max: 4, drop: "pitcher_pod", min: 1, max: 1 },
            "minecraft:torchflower_crop": { max: 7, drop: "torchflower", seeds: "torchflower_seeds", min: 1, max: 1 },
            "minecraft:sweet_berry_bush": { max: 3, drop: "sweet_berries", min: 2, max: 3 }
          };
          const crop = crops[ID];
          if (!crop) return;
          const currentGrowth = block.permutation.getState("growth");
          if (currentGrowth < crop.max) return;
          const mainCount = Math.floor(Math.random() * (crop.max - crop.min + 1)) + crop.min;
          source.dimension.spawnItem(
            new ItemStack(`minecraft:${crop.drop}`, mainCount),
            {
              x: block.location.x + 0.5,
              y: block.location.y + 1,
              z: block.location.z + 0.5
            }
          );
          if (crop.seeds) {
            const seedCount = Math.floor(Math.random() * 3); 
            if (seedCount > 0) {
              source.dimension.spawnItem(
                new ItemStack(`minecraft:${crop.seeds}`, seedCount),
                {
                  x: block.location.x + 0.5,
                  y: block.location.y + 1,
                  z: block.location.z + 0.5
                }
              );
            }
          }

          system.runTimeout(() => {
            block.dimension.spawnParticle("dive_hw:hoe_particle", {
              x: block.location.x,
              y: block.location.y + 1,
              z: block.location.z
            });
            const newPerm = block.permutation.withState("growth", 0);
            source.dimension.setBlockPermutation(block.location, newPerm);
          }, 2);
        }
      }
    }
  ]
});


dwInjections.set("dive_hw:hacker_wand", {
  hasCooldown: true,
  attacks: [
    {
      testCooldown: true,
      injectorType: "onUse",
      toInject: (source) => {
        const {
          hacker_wand: {
            maxTeleportRange,
            secondsToStart,
            particleErrorFindObjective,
            particleGlitch
          }
        } = dynamicWeaponsConfig;
        const delayTicks = secondsToStart * 20;
        system.runTimeout(() => {
          const hit = source.getBlockFromViewDirection({ maxDistance: maxTeleportRange });
          if (!hit?.block) {
            const rel = getRelative(source, source.getViewDirection(), [1, 0, 0], source.getHeadLocation().y);
            source.dimension.spawnParticle(particleErrorFindObjective, rel);
            source.sendMessage("§cNo target found within range.");
            return;
          }
          const targetBlock = hit.block;
          const above = targetBlock.above();
          const canTP = above.isAir && above.above().isAir;
          if (!canTP) {
            source.dimension.spawnParticle(particleErrorFindObjective, above.location);
            source.sendMessage("§cCan't teleport inside solid blocks.");
            return;
          }
          source.teleport(above.location, { checkForBlocks: true });
          source.dimension.spawnParticle(particleGlitch, above.location);
        }, delayTicks);
      }
    }
  ]
});

function damageEquippedItem(player, slot = EquipmentSlot.Mainhand) {
    if (!(player instanceof Player)) return;
    const equippable = player.getComponent("minecraft:equippable");
    if (!equippable) return;
    const equipped = equippable.getEquipmentSlot(slot);
    if (!equipped || !equipped.hasItem()) return;
    if (player.getGameMode() === GameMode.creative) return;
    const itemStack = equipped.getItem();
    const durability = itemStack.getComponent("minecraft:durability");
    if (!durability) return;
    const enchantable = itemStack.getComponent("minecraft:enchantable");
    const unbreakingLevel = enchantable?.getEnchantment("unbreaking")?.level ?? 0;
    const damageChance = durability.getDamageChance(unbreakingLevel) / 100;
    if (Math.random() > damageChance) return;
    if (durability.damage + 1 >= durability.maxDurability) {
        equipped.setItem(undefined);
        player.playSound("random.break");
    } else {
        durability.damage++;
        equipped.setItem(itemStack);
    }
}
const jetpackUseTicks = new Map(); // <player.id, tickCount>
dwInjections.set("dive_hw:hacker_jetpack", {
  hasCooldown: false,
  attacks: [],
    setInterval: (source) => {
    const { hacker_jetpack: { particleFly, soundFly, soundFlyDelay } } = dynamicWeaponsConfig;
    const last = dwICache.wait.get(source) || 0;
    dwICache.wait.set(source, last + 1);
    source.addEffect("slow_falling", 20, { amplifier: 1, showParticles: false });
    if (last > soundFlyDelay) {
      dwICache.wait.delete(source);
    }
    if (source.hasTag("jetpack_rider_hacker")) {
      if (!dwICache.wait.has(source)) source.playSound(soundFly);
      source.addEffect("levitation", 10, { amplifier: 2, showParticles: false });
      source.dimension.spawnParticle(particleFly, source.location);
      const ticks = jetpackUseTicks.get(source.id) ?? 0;
      if (ticks >= 40) {
        damageEquippedItem(source, EquipmentSlot.Chest);
        jetpackUseTicks.set(source.id, 0);
      } else {
        jetpackUseTicks.set(source.id, ticks + 1);
      }
    }
    if (source.hasTag("jetpack_descend_hacker")) {
      source.addEffect("slow_falling", 20, { amplifier: 1, showParticles: false });
      source.dimension.spawnParticle(particleFly, source.location);
    }
    if (source.isOnGround) {
      source.removeTag("jetpack_rider_hacker");
      source.removeTag("jetpack_descend_hacker");
      jetpackUseTicks.delete(source.id);
    }
  }
});

dwICache.wait = new WeakMap();
dwICache.excludes = new Set();
dwICache.includes = new Set();