import { EquipmentSlot, GameMode, system, world, } from "@minecraft/server";
import { namespace } from "../../../config/_config";
import { getItemInSlot, removeItemFromInventory } from "../../helper/utils";
// Crop class defines crop blocks that have multiple growth states and can be interacted with using specific items or fertilizers.
export class Crop {
    // Constructor to initialize a Crop with its properties
    constructor(config) {
        this.config = config;
    }
    static registerBehavior(config) {
        const crop = new Crop(config);
        Crop.blocks.push(crop);
    }
    // Method to initialize the crop system and register the custom block component
    static initialize() {
        world.beforeEvents.worldInitialize.subscribe((event) => {
            event.blockComponentRegistry.registerCustomComponent(`${namespace}:crop_grow`, {
                onRandomTick: Crop.handleRandomTick, // Handles random growth ticks
                //onPlayerInteract: Crop.handlePlayerInteract, // Handles player interactions (fertilization, harvesting)
            });
        });
        world.beforeEvents.playerInteractWithBlock.subscribe((event) => {
            if (event.isFirstEvent) {
                Crop.handlePlayerInteract(event);
            }
        });
    }
    // Method to find a crop by its identifier (block ID)
    static getCropByIdentifier(identifier) {
        return Crop.blocks.find((crop) => crop.config.id === identifier);
    }
    // Handle crop growth on random tick
    static handleRandomTick(event) {
        const crop = Crop.getCropByIdentifier(event.block.typeId);
        if (crop) {
            Crop.growCrop(event, crop); // Apply growth logic for the crop
        }
    }
    // Handle player interaction (e.g., fertilizer use or harvesting)
    static handlePlayerInteract(event) {
        const crop = Crop.getCropByIdentifier(event.block.typeId);
        if (crop) {
            const wasInteracted = Crop.interactWithCrop(event, crop); // Check if the player interacted with the crop
            if (!wasInteracted) {
                Crop.fertilizeCrop(event, crop); // If no interaction occurred, try to fertilize the crop
            }
        }
    }
    // Method to grow the crop by incrementing its growth state
    static growCrop(event, crop) {
        const block = event.block;
        const state = block.permutation.getState(`${namespace}:grow_state`); // Get the current growth state
        if (state === undefined || typeof state !== "number" || state >= crop.config.states)
            return;
        // Increase the growth state based on the growth rate multiplier
        if (Math.random() < crop.config.growthRateMultiplier) {
            Crop.updateGrowState(block, state + 1, crop.config.syncWithAdjacent);
        }
    }
    // Method to fertilize the crop using specific items
    static fertilizeCrop(event, crop) {
        const block = event.block;
        const player = event.player;
        if (!player)
            return;
        const item = getItemInSlot(player, EquipmentSlot.Mainhand); // Get the item in the player's hand
        const state = block.permutation.getState(`${namespace}:grow_state`); // Get the current growth state
        const isValidFertilizer = Array.isArray(crop.config.fertilizer)
            ? crop.config.fertilizer.includes(item?.typeId ?? "")
            : crop.config.fertilizer === item?.typeId;
        if (!isValidFertilizer || state === undefined || typeof state !== "number")
            return;
        if (player.getGameMode() === GameMode.creative) {
            Crop.instantGrow(block, crop); // Instantly grow the crop in creative mode
        }
        else {
            Crop.advanceGrowth(block, state, crop, player, item); // Otherwise, advance growth normally
        }
    }
    // Instantly grow the crop to its final state
    static instantGrow(block, crop) {
        Crop.updateGrowState(block, crop.config.states, crop.config.syncWithAdjacent);
        system.runTimeout(() => {
            block.dimension.spawnParticle("minecraft:crop_growth_emitter", block.center());
            block.dimension.playSound("item.bone_meal.use", block.center());
        }, 1);
    }
    // Advance the crop's growth state and remove the fertilizer item from the player's inventory
    static advanceGrowth(block, state, crop, player, item) {
        if (state < crop.config.states) {
            system.runTimeout(() => {
                block.dimension.spawnParticle("minecraft:crop_growth_emitter", block.center());
                block.dimension.playSound("item.bone_meal.use", block.center());
                Crop.updateGrowState(block, state + 1, crop.config.syncWithAdjacent); // Update the growth state
            }, 1);
            if (player.getGameMode() !== GameMode.creative) {
                system.runTimeout(() => {
                    removeItemFromInventory(player, item.typeId); // Remove the item if not in creative mode
                }, 1);
            }
        }
    }
    // Handle interaction with the crop (harvesting or other interactions)
    static interactWithCrop(event, crop) {
        const block = event.block;
        const state = block.permutation.getState(`${namespace}:grow_state`);
        if (!crop.config.interact || state === undefined || typeof state !== "number")
            return false;
        const interactOption = crop.config.interact.find((option) => option.triggerState === state); // Find matching interaction
        if (!interactOption || !event.player)
            return false;
        const playerItem = getItemInSlot(event.player, EquipmentSlot.Mainhand); // Get player's held item
        const items = Array.isArray(interactOption.item) ? interactOption.item : [interactOption.item];
        const correctItem = items.includes("all") ||
            (items.includes("hand") && !playerItem) ||
            items.includes(playerItem?.typeId ?? "");
        if (!correctItem)
            return false; // Exit if the player isn't using the correct item
        // Perform the interaction (e.g., harvesting)
        Crop.performInteraction(block, interactOption);
        Crop.interactWithAdjacentBlocks(event, crop, interactOption);
        return true;
    }
    // Method to perform the interaction, such as changing the growth state or spawning loot
    static performInteraction(block, interactOption) {
        const nextState = interactOption.nextState ?? 0; // Default to state 0 if nextState is not defined
        Crop.updateGrowState(block, nextState, interactOption.syncWithAdjacent && nextState < 5);
        system.runTimeout(() => {
            if (interactOption.lootTable) {
                block.dimension.runCommandAsync(`loot spawn ${block.center().x} ${block.center().y} ${block.center().z} loot "${interactOption.lootTable}"`);
            }
            if (interactOption.effects?.sound) {
                block.dimension.playSound(interactOption.effects.sound, block.center());
            }
            if (interactOption.effects?.particle) {
                block.dimension.spawnParticle(interactOption.effects.particle, block.center());
            }
        }, 1);
    }
    // Update the crop's growth state and sync with adjacent blocks if required
    static updateGrowState(block, newState, syncWithAdjacent = false) {
        system.runTimeout(() => {
            block.setPermutation(block.permutation.withState(`${namespace}:grow_state`, newState));
        }, 1);
        if (syncWithAdjacent) {
            Crop.syncWithAdjacentBlocks(block, newState); // Sync growth state with adjacent blocks
        }
    }
    // Sync the crop's growth state with adjacent blocks (above and below)
    static syncWithAdjacentBlocks(block, newState) {
        const adjacentBlocks = [block.below(), block.above()]; // Check blocks above and below
        adjacentBlocks.forEach((adjacentBlock) => {
            if (adjacentBlock) {
                const adjacentState = adjacentBlock.permutation.getState(`${namespace}:grow_state`);
                if (adjacentState !== undefined &&
                    typeof adjacentState === "number" &&
                    adjacentState < newState) {
                    system.runTimeout(() => {
                        adjacentBlock.setPermutation(adjacentBlock.permutation.withState(`${namespace}:grow_state`, newState));
                    }, 1);
                }
            }
        });
    }
    // Sync interaction behavior with adjacent blocks
    static interactWithAdjacentBlocks(event, crop, interactOption) {
        if (!interactOption.syncWithAdjacent)
            return;
        const adjacentBlocks = [event.block.below(), event.block.above()]; // Check adjacent blocks
        adjacentBlocks.forEach((adjacentBlock) => {
            if (adjacentBlock && adjacentBlock.typeId === crop.config.id) {
                const adjacentState = adjacentBlock.permutation.getState(`${namespace}:grow_state`);
                if (adjacentState === interactOption.triggerState) {
                    Crop.performInteraction(adjacentBlock, interactOption); // Perform the same interaction on adjacent block
                }
            }
        });
    }
}
Crop.blocks = [];
