import * as mc from "@minecraft/server";
import { itemManager, randomNum } from "../sgs_farm_lib";
import { cropBlocks } from "./sgs_farm_cropconfig";

const HARVEST_WITH_SICKLE = "mob.sheep.shear";
const SOUND_OPTIONS = { pitch: 1.0, volume: 5.0, };

export class vineManager {

    static beforeplaceFrame(data) {
        data.permutationToPlace = placeNewFrameBlock(data.block, data.permutationToPlace);
    }

    static interactFrame(data) {
        const block = data.block;
        const player = data.player;

        const mainhand = player.getComponent(mc.EntityEquippableComponent.componentId).getEquipmentSlot(mc.EquipmentSlot.Mainhand);
        const heldItem = mainhand.getItem();
        if (heldItem == undefined) return;

        if (heldItem.typeId == "sgs_farm:vine_frame") {

            let topBlock = block;
            for (let index = 0; index < 5; index++) {
                if (topBlock.isAir) {
                    topBlock.setPermutation(placeNewFrameBlock(topBlock, block.permutation));
                    block.dimension.playSound("block.scaffolding.place", topBlock.center());
                    return;
                }
                topBlock = topBlock.above();
            }
        }

        const vinedata = cropBlocks.find((f) => f.seedID == heldItem.typeId);
        if (vinedata == undefined) return;  //seedID not found
        if (vinedata.type != "vine") return;    //seed not a vine
        if (block.permutation.getState("sgs_farm:height") > 0) return;   //can only place vine seeds on base level frame above farmland

        block.dimension.playSound("place.azalea_leaves", block.center());
        block.setPermutation(mc.BlockPermutation.resolve(heldItem.typeId.substring(0, heldItem.typeId.length - 5),
            {
                "sgs_farm:growth": 0,
                "sgs_farm:height": 0
            }));

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

    static destroyFrame(data) {

        const block = data.block;

        const northConnects = data.destroyedBlockPermutation.getState("sgs_farm:north");
        const eastConnects = data.destroyedBlockPermutation.getState("sgs_farm:east");
        const southConnects = data.destroyedBlockPermutation.getState("sgs_farm:south");
        const westConnects = data.destroyedBlockPermutation.getState("sgs_farm:west");

        const north = block.north();
        const east = block.east();
        const south = block.south();
        const west = block.west();

        if (northConnects && north.hasTag("sgs_farm_vine_frame")) north.setPermutation(north.permutation.withState('sgs_farm:south', 0));
        if (eastConnects && east.hasTag("sgs_farm_vine_frame")) east.setPermutation(east.permutation.withState('sgs_farm:west', 0));
        if (southConnects && south.hasTag("sgs_farm_vine_frame")) south.setPermutation(south.permutation.withState('sgs_farm:north', 0));
        if (westConnects && west.hasTag("sgs_farm_vine_frame")) west.setPermutation(west.permutation.withState('sgs_farm:east', 0));
    }


    static tick(block) {
        if (block.permutation.getState("sgs_farm:height") > 0) return;   //only want to tick the base level plant for growing
        const data = cropBlocks.find((f) => f.blockID == block.typeId);
        if (data == undefined) return;

        //get crop growth height
        let cropHeight = 0;
        for (let index = 0; index < data.height; index++) {

            if (block.above(index).typeId == block.typeId)
            {
                cropHeight++;
            }
            else break;
        }

        //initial growth check for existing vine stack
        for (let index = 0; index < cropHeight; index++) {

            const vineBlock = block.above(index);
            const stage = getGrowthStage(vineBlock, data);

            const num = randomNum(0, data.growChance.denominator);
            if (stage < data.maxStage && num < data.growChance.numerator) {
                vineBlock.setPermutation(vineBlock.permutation.withState(data.stateID, stage + 1));
            }
        }

        //secondary to growth check to place extra block on top stack 
        if (cropHeight < data.height) {
            const num = randomNum(0, data.growChance.denominator);
            if (num < data.growChance.numerator) {
                if (block.above(cropHeight).typeId == "sgs_farm:vine_frame") {
                    const topBlock = block.above(cropHeight);

                    //set height level options for crop cosmetics
                    let height = 0;
                    if (cropHeight == 1) height = 1;
                    if (cropHeight > 1) height = 2;
                    topBlock.setPermutation(placeNewCropBlock(topBlock, block.permutation, height));
                }
            }
        }
    }

    static interactCrop(block, player) {

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

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

    //interact with sickle
    static sickle(block, data, player) {
        let setStage = 0;
        player.playSound(HARVEST_WITH_SICKLE, SOUND_OPTIONS);
        block.setPermutation(block.permutation.withState(data.stateID, setStage));
        if (data.height == 2) block.above(1).setPermutation(mc.BlockPermutation.resolve("minecraft:air"));

        const dropItem = new mc.ItemStack(data.cropID, 1);
        const { x, y, z } = block.location;
        block.dimension.spawnItem(dropItem, { x: x + 0.5, y: y + 0.5, z: z + 0.5 });
    }

    //interact with bone meal
    static bonemeal(block, data, player, mainhand, heldItem, stage) {
        let setStage = stage + 3;
        if (setStage > data.maxStage) setStage = data.maxStage;
        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() == mc.GameMode.creative) return;
        mainhand.setItem(itemManager.reduceAmount(heldItem, 1));
    }

}

function getGrowthStage(block, cropData) {
    return block.permutation.getState(cropData.stateID);
}

function placeNewFrameBlock(block, permutation) {

    const below = block.below();
    const north = block.north();
    const east = block.east();
    const south = block.south();
    const west = block.west();

    let northConnects = north.hasTag("sgs_farm_vine");
    let southConnects = south.hasTag("sgs_farm_vine");
    let eastConnects = east.hasTag("sgs_farm_vine");
    let westConnects = west.hasTag("sgs_farm_vine");

    let height = 1;
    if (below.typeId == "minecraft:farmland") {
        height = 0;
        northConnects = false;
        southConnects = false;
        eastConnects = false;
        westConnects = false;
    }

    //set connectors to neighbouring bare vine frames
    if (northConnects && north.hasTag("sgs_farm_vine_frame")) north.setPermutation(north.permutation.withState('sgs_farm:south', 1));
    if (eastConnects && east.hasTag("sgs_farm_vine_frame")) east.setPermutation(east.permutation.withState('sgs_farm:west', 1));
    if (southConnects && south.hasTag("sgs_farm_vine_frame")) south.setPermutation(south.permutation.withState('sgs_farm:north', 1));
    if (westConnects && west.hasTag("sgs_farm_vine_frame")) west.setPermutation(west.permutation.withState('sgs_farm:east', 1));

    return mc.BlockPermutation.resolve(permutation.type.id, { 'sgs_farm:height': height, 'sgs_farm:north': northConnects ? 1 : 0, 'sgs_farm:south': southConnects ? 1 : 0, 'sgs_farm:east': eastConnects ? 1 : 0, 'sgs_farm:west': westConnects ? 1 : 0 });
}

function placeNewCropBlock(block, permutation, height) {

    const north = block.north();
    const east = block.east();
    const south = block.south();
    const west = block.west();

    let northConnects = north.hasTag("sgs_farm_vine_frame");
    let southConnects = south.hasTag("sgs_farm_vine_frame");
    let eastConnects = east.hasTag("sgs_farm_vine_frame");
    let westConnects = west.hasTag("sgs_farm_vine_frame");

    //set connectors to neighbouring bare vine frames
    if (northConnects) north.setPermutation(north.permutation.withState('sgs_farm:south', 1));
    if (eastConnects) east.setPermutation(east.permutation.withState('sgs_farm:west', 1));
    if (southConnects) south.setPermutation(south.permutation.withState('sgs_farm:north', 1));
    if (westConnects) west.setPermutation(west.permutation.withState('sgs_farm:east', 1));

    return mc.BlockPermutation.resolve(permutation.type.id, {
        'sgs_farm:height': height
    });
}