import { world, GameMode, system } from '@minecraft/server';
import { updateBlock } from '../utils/block';
import { consumeEquipped } from '../utils/item';

const playerEquipmentCache = new WeakMap();

const Utils = {
  getPlayerEquipment(player) {
    if (!playerEquipmentCache.has(player)) {
      playerEquipmentCache.set(player, player.getComponent('equippable'));
    }
    return playerEquipmentCache.get(player);
  },

  getSelectedItem(player) {
    const equip = this.getPlayerEquipment(player);
    return equip?.getEquipment('Mainhand') ?? null;
  },

  consumeItem(player, item) {
    if (player.getGameMode() === GameMode.creative) return;
    const equip = this.getPlayerEquipment(player);
    consumeEquipped(equip, item);
  },

  setBlockState(block, stateName, value) {
    try {
      const newPerm = block.permutation.withState(stateName, value);
      block.setPermutation(newPerm);
    } catch (err) {
      updateBlock(block, { [stateName]: value });
    }
  },

  playSound(block, sound) {
    try { 
      block.dimension.playSound(sound, block.location); 
    } catch (e) {}
  },

  spawnParticle(block, particle, offset = { x: 0, y: 0, z: 0 }) {
    try {
      const loc = block.location;
      block.dimension.spawnParticle(particle, {
        x: loc.x + 0.5 + offset.x,
        y: loc.y + 0.5 + offset.y,
        z: loc.z + 0.5 + offset.z
      });
    } catch (e) {}
  },

  spawnLoot(block) {
    const { dimension, location, typeId } = block;
    const name = typeId.split(":")[1];
    try {
      dimension.runCommand(`loot spawn ${location.x} ${location.y} ${location.z} loot "crop/${name}"`);
    } catch (e) {}
  },

  saplingConfig: {
    palm: {
      structures: Array.from({ length: 12 }, (_, i) => {
        const size = i < 4 ? 'small' : i < 8 ? 'medium' : 'big';
        const num = (i % 4) + 1;
        return { name: `palm_${size}${num}`, offset: [-2, 0, -2] };
      })
    },
    banana: {
      structures: [
        ...Array.from({ length: 2 }, (_, i) => ({ name: `banana_small${i + 1}`, offset: [-2, 0, -2] })),
        ...Array.from({ length: 2 }, (_, i) => ({ name: `banana_medium${i + 1}`, offset: [-2, 0, -2] })),
        ...Array.from({ length: 2 }, (_, i) => ({ name: `banana_big${i + 1}`, offset: [-2, 0, -2] }))
      ]
    },
    papaya: {
      structures: ['small', 'medium', 'big'].flatMap(size =>
        [1, 2].map(num => ({ name: `papaya_${size}${num}`, offset: [-1, 0, -1] }))
      )
    },
    pear: {
      structures: [
        { name: 'pear_tree', offset: [-2, 0, -2] },
        { name: 'pear_tree1', offset: [-2, 0, -2] }
      ]
    },
    peach: {
      structures: [
        { name: 'peach_tree1', offset: [-3, 0, -4] },
        { name: 'peach_tree', offset: [-1, 0, -1] }
      ]
    },
    orange: {
      structures: [
        { name: 'orange_tree', offset: [-2, 0, -2] },
        { name: 'orange_tree1', offset: [-2, 0, -2] }
      ]
    },
    mango: {
      structures: [
        { name: 'mango_tree', offset: [-2, 0, -2] },
        { name: 'mango_tree1', offset: [-3, 0, -5] }
      ]
    },
    jackfruit: {
      structures: [
        { name: 'jackfruit_tree', offset: [-3, 0, -3] },
        { name: 'jackfruit_tree1', offset: [-3, 0, -3] }
      ]
    },
    lemon: {
      structures: [
        { name: 'lemon_tree', offset: [-2, 0, -2] },
        { name: 'lemon_tree1', offset: [-2, 0, -2] }
      ]
    },
    guava: {
      structures: [
        { name: 'guava_tree', offset: [-2, 0, -2], weight: 5 },
        { name: 'guava_tree_vanilla', offset: [-2, 0, -2], weight: 1 }
      ]
    },
    avocado: {
      structures: [
        { name: 'avocado_tree', offset: [-2, 0, -2] },
        { name: 'avocado_tree1', offset: [-2, 0, -2] }
      ]
    },
    acorn: {
      structures: [
        { name: 'acorn_tree', offset: [-2, 0, -2], weight: 3 },
        { name: 'acorn_tree_vanilla', offset: [-2, 0, -2], weight: 1 }
      ]
    },
    apple: {
      structures: [
        { name: 'apple_tree', offset: [-2, 0, -2] },
        { name: 'apple_tree1', offset: [-2, 0, -2] }
      ]
    }
  },

  getSaplingConfig(saplingTypeId) {
    const saplingName = saplingTypeId.split(':')[1].replace('_sapling', '');
    return this.saplingConfig[saplingName] ?? null;
  },

  getRandomStructure(saplingTypeId) {
    const config = this.getSaplingConfig(saplingTypeId);
    if (!config) return null;

    const { structures } = config;
    const totalWeight = structures.reduce((sum, s) => sum + (s.weight ?? 1), 0);
    let random = Math.random() * totalWeight;
    
    for (const struct of structures) {
      random -= (struct.weight ?? 1);
      if (random <= 0) return struct;
    }
    
    return structures[structures.length - 1];
  },

  canGrow(block) {
    try {
      const blockAbove = block.dimension.getBlock({ 
        x: block.location.x, 
        y: block.location.y + 1, 
        z: block.location.z 
      });
      return blockAbove?.typeId === 'minecraft:air' || blockAbove?.isAir;
    } catch (e) {
      return false;
    }
  },

  spawnTree(block) {
    const structData = this.getRandomStructure(block.typeId);
    if (!structData) return;
    
    const { name, offset } = structData;
    const { dimension, location } = block;
    
    try {
      block.setType('minecraft:air');
      dimension.runCommand(
        `structure load ${name} ${location.x + offset[0]} ${location.y + offset[1]} ${location.z + offset[2]} 0_degrees none true`
      );
      this.spawnParticle(block, 'minecraft:crop_growth_emitter', { y: 1 });
      this.playSound(block, 'block.wood.place');
    } catch (e) {}
  }
};

const createGrowthComponent = (maxLevel, isBush = false, isStalk = false, isVine = false) => ({
  onPlayerInteract: e => {
    const { player, block } = e;
    const selectedItem = Utils.getSelectedItem(player);
    const level = block.permutation.getState("peach:growth");

    if (isBush && level === 4) {
      Utils.setBlockState(block, "peach:growth", level - 2);
      player.playSound("block.sweet_berry_bush.pick");
      Utils.spawnLoot(block);
      return;
    }

    if (isVine && level === 5) {
      Utils.setBlockState(block, "peach:growth", level - 3);
      player.playSound("block.sweet_berry_bush.pick");
      Utils.spawnLoot(block);
      return;
    }

    if (isStalk && level >= 2) {
      Utils.setBlockState(block, "peach:growth", level - 2);
      player.playSound("block.sweet_berry_bush.pick");
      Utils.spawnLoot(block);
      return;
    }

    if (selectedItem?.typeId === "minecraft:bone_meal" && level < maxLevel) {
      Utils.consumeItem(player, selectedItem);
      Utils.spawnParticle(block, 'minecraft:crop_growth_emitter');
      Utils.setBlockState(block, "peach:growth", level + 1);
      player.playSound("item.bone_meal.use");
    }
  },

  onRandomTick: e => {
    const { block } = e;
    try {
      const level = block.permutation.getState("peach:growth");
      if (level >= maxLevel) return;

      if (Math.random() < 0.2) {
        system.runTimeout(() => {
          if (!block.isValid()) return;
          const current = block.permutation.getState("peach:growth");
          if (current < maxLevel) {
            Utils.setBlockState(block, "peach:growth", current + 1);
          }
        }, Math.floor(Math.random() * 10) + 5);
      }
    } catch (err) {}
  }
});

const saplingComponent = {
  onPlayerInteract: e => {
    const { player, block } = e;
    const selectedItem = Utils.getSelectedItem(player);
    if (selectedItem?.typeId !== 'minecraft:bone_meal') return;

    if (!Utils.canGrow(block)) {
      Utils.spawnParticle(block, 'minecraft:crop_growth_emitter');
      player.playSound('item.bone_meal.use');
      Utils.consumeItem(player, selectedItem);
      return;
    }

    Utils.consumeItem(player, selectedItem);
    Utils.spawnParticle(block, 'minecraft:crop_growth_emitter');
    player.playSound('item.bone_meal.use');

    if (Math.random() < 0.17) {
      system.runTimeout(() => {
        if (block.isValid()) Utils.spawnTree(block);
      }, 2);
    }
  },

  onRandomTick: e => {
    const { block } = e;
    try {
      if (!Utils.canGrow(block)) return;

      if (Math.random() < 0.32) {
        system.runTimeout(() => {
          if (block.isValid() && Utils.canGrow(block)) {
            Utils.spawnTree(block);
          }
        }, Math.floor(Math.random() * 10) + 5);
      }
    } catch (err) {}
  }
};

world.beforeEvents.worldInitialize.subscribe(init => {
  const registry = init.blockComponentRegistry;
  
  registry.registerCustomComponent('peach:crop_logic', createGrowthComponent(3));
  registry.registerCustomComponent('peach:bigCrop_logic', createGrowthComponent(5));
  registry.registerCustomComponent('peach:bush_logic', createGrowthComponent(4, true, false, false));
  registry.registerCustomComponent('peach:stalk_logic', createGrowthComponent(2, false, true, false));
  registry.registerCustomComponent('peach:vine_logic', createGrowthComponent(5, false, false, true));
  registry.registerCustomComponent('peach:sapling_logic', saplingComponent);
});