import { EquipmentSlot, EntityEquippableComponent, GameMode } from '@minecraft/server';
import { getRandomInt, highlightBlock, itemManager, randomNum } from '../sgs_farm_lib';
import * as mc from "@minecraft/server";
import { treeBlocks } from './sgs_farm_cropconfig';

const STRUCTURE_SUFFIX = ["_1", "_2", "_3"];
const STRUCTURE_MIRROR = ["None", "X", "XZ", "Z"];
const STRUCTURE_ROTATE = ["None", "Rotate90", "Rotate180", "Rotate270"];

export class treeManager {
    
    static beforeplaceLeaves(data) {
        data.permutationToPlace = mc.BlockPermutation.resolve(data.permutationToPlace.type.id, {'sgs_farm:player_placed': 1 });
    }

    //tick data
    static tick(block) {
        //get the crop data
        const data = treeBlocks.find((f) => f.blockID == block.typeId);
        if (data == undefined) return;
        if (block.permutation.getState('sgs_farm:player_placed') == 1) return;
        const stage = this.getGrowthStage(block, data);
        //reset stage one update after growth hits max
        if (stage >= data.maxStage) {
            block.setPermutation(block.permutation.withState(data.stateID, 0));
            return;
        }
        //get the random number
        const num = randomNum(0, data.growChance.denominator);
        //return if the random number is more than the numerator
        if (num > data.growChance.numerator) return;

        block.setPermutation(block.permutation.withState(data.stateID, stage + 1));

        try {
            if (stage + 1 == data.maxStage) {
                const below = block.below(1);
                let growFruit = true;
                if (below.isAir) {
                    //check sorroundings to limit total natural fruit growth
                    if (below.north().typeId == data.cropID) growFruit = false;
                    if (below.south().typeId == data.cropID) growFruit = false;
                    if (below.east().typeId == data.cropID) growFruit = false;
                    if (below.west().typeId == data.cropID) growFruit = false;

                    if (growFruit) below.setPermutation(mc.BlockPermutation.resolve(data.cropID));
                }
            }
        } catch (error) {

        }

    }

    static interact(block, player) {
        const data = treeBlocks.find((f) => f.blockID == block.typeId);
        if (data == undefined) return;
        const mainhand = player.getComponent(EntityEquippableComponent.componentId).getEquipmentSlot(EquipmentSlot.Mainhand);
        const heldItem = mainhand.getItem();
        const stage = this.getGrowthStage(block, data);

        if (stage >= data.maxStage) {
            return;
        }
        else {
            if (heldItem != undefined && stage != data.maxStage && heldItem.typeId == "minecraft:bone_meal" && data.bonemealable) {
                this.bonemeal(block, data, player, mainhand, heldItem, stage);
            }
        }
    }

    //interact with bone meal
    static bonemeal(block, data, player, mainhand, heldItem, stage) {
        let setStage = stage + 3;
        if (setStage > data.maxStage) {
            setStage = data.maxStage;

            const below = block.below(1);
            if (below.isAir) {
                below.setPermutation(mc.BlockPermutation.resolve(data.cropID));
            }
        }
        try {
            block.dimension.spawnParticle("minecraft:crop_growth_emitter", block.center());
        } catch { }
        block.dimension.playSound("item.bone_meal.use", block.center());

        block.setPermutation(block.permutation.withState(data.stateID, setStage));

        if (player.getGameMode() == GameMode.creative) return;
        mainhand.setItem(itemManager.reduceAmount(heldItem, 1));
    }

    static tickSapling(block) {
        const data = treeBlocks.find((f) => f.saplingID == block.typeId);
        if (data == undefined) return;

        const num = randomNum(0, 5);
        if (num > data.growChance.numerator) return;

        const name = "sgs_farm/" + data.saplingID.replace(":", "_") + STRUCTURE_SUFFIX[Math.floor(Math.random() * STRUCTURE_SUFFIX.length)];
        this.placeStructureCentered(name, block);
    }

    static interactSapling(block, player) {
        const data = treeBlocks.find((f) => f.saplingID == block.typeId);
        if (data == undefined) return;
        const mainhand = player.getComponent(EntityEquippableComponent.componentId).getEquipmentSlot(EquipmentSlot.Mainhand);
        const heldItem = mainhand.getItem();

        if (heldItem != undefined && heldItem.typeId == "minecraft:bone_meal" && data.bonemealable) {

            const name = "sgs_farm/" + data.saplingID.replace(":", "_") + STRUCTURE_SUFFIX[Math.floor(Math.random() * STRUCTURE_SUFFIX.length)];
            this.placeStructureCentered(name, block);
        }
    }

    static getGrowthStage(block, cropData) {
        //return the block's growth stage
        return block.permutation.getState(cropData.stateID);
    }

    static placeStructureCentered(name, block) {
        const structureManager = mc.world.structureManager;
        const structure = structureManager.get(name);
        const size = structure.size;
        const location = block.location;
        const offset = Math.floor(size.x / 2);
        const placelocation = { x: location.x - offset, y: location.y, z: location.z - offset };
        const dimension = block.dimension;

        let isAir = true;
        for (let x = 0; x < size.x; x++) {
            for (let y = 1; y < size.y; y++) {
                for (let z = 0; z < size.z; z++) {
                    if (!dimension.getBlock({ x: location.x + x - offset, y: location.y + y, z: location.z + z - offset }).isAir) isAir = false;

                    //randomize leaf growth states on spawn
                    let permutation = structure.getBlockPermutation({ x: x, y: y, z: z });
                    if (permutation != undefined && permutation.getState("sgs_farm:growth") != undefined) {
                        structure.setBlockPermutation({ x: x, y: y, z: z }, permutation.withState("sgs_farm:growth", getRandomInt(0, 6)));
                    }
                }
            }
        }

        if (isAir) {
            const rotate = STRUCTURE_ROTATE[Math.floor(Math.random() * STRUCTURE_ROTATE.length)];
            const mirror = STRUCTURE_MIRROR[Math.floor(Math.random() * STRUCTURE_MIRROR.length)];

            structureManager.place(structure, dimension, placelocation, { mirror: mirror, rotation: rotate });
        }
    }
}
