import { BlockComponentTypes, BlockPermutation, Direction, MolangVariableMap } from "@minecraft/server";
import { flipDir, getADirection, isAxisVertical, offsetPos, offsetVec } from "../util/dirUtils";
import { McBlocks } from "../reg/mcBlocks";
import { SuppStates } from "../reg/suppStates";
import { random } from "../util/mthUtils";
import { McStates } from "../reg/mcStates";
import { FillingType, getJarFillingType, getJarVolume, tryTransferJarContent } from "./jarStuff";
import { hasWater } from "../util/blockProperties";
import { SuppParticles } from "../reg/suppParticles";
import { worldProxy } from "../worldProxy";
import { McParticles } from "../reg/mcParticles";
function extractFromContainer(block, behindBlock, dir) {
    const inventory = behindBlock.getComponent(BlockComponentTypes.Inventory);
    if (inventory && inventory.container) {
        const inv = inventory.container;
        for (let i = 0; i < inv.size; i++) {
            const slot = inv.getSlot(i);
            const stack = slot.getItem();
            if (stack) {
                if (slot.amount <= 1) {
                    slot.setItem(undefined);
                }
                else
                    slot.amount -= 1;
                const newStack = stack.clone();
                newStack.amount = 1;
                let spawnPos;
                if (dir == Direction.Up) {
                    spawnPos = block.center();
                }
                else if (dir == Direction.Down) {
                    spawnPos = offsetVec(block.center(), dir, 12 / 16);
                }
                else {
                    spawnPos = block.bottomCenter();
                }
                const itemEntity = block.dimension.spawnItem(newStack, spawnPos);
                itemEntity.clearVelocity();
                if (itemEntity && dir == Direction.Up) {
                    //calculate a random angle and from it
                    itemEntity.applyImpulse(getTiltedVector(0.6, 0.25, 1.8));
                }
                block.dimension.playSound("random.pop", spawnPos, { pitch: random(0.65, 0.70), volume: 1 });
                return;
            }
        }
    }
}
function getTiltedVector(maxAngle, length = 1, bias = 2) {
    // Precompute cosine of max angle
    const cosMaxAngle = Math.cos(maxAngle);
    // Generate biased random y-component (no trig needed)
    const y = length * (Math.pow(Math.random(), 1 / (bias + 1)) * (1 - cosMaxAngle) + cosMaxAngle);
    // Remaining length to distribute to x and z components
    const remainingLength = Math.sqrt(length * length - y * y);
    // Random angle around vertical axis
    const angle = Math.random() * Math.PI * 2;
    const sinAngle = Math.sin(angle);
    const cosAngle = Math.cos(angle);
    return {
        x: remainingLength * cosAngle,
        y: y,
        z: remainingLength * sinAngle
    };
}
function sprinkleAround(block, behind) {
    if (!hasWater(behind))
        return;
    if (Math.random() < 0.2) {
        //pick a random block in a 5x5x5 area around the block. if its farmland irrigate it
        const x = Math.floor(Math.random() * 9) - 4;
        const y = Math.floor(Math.random() * 5) - 2;
        const z = Math.floor(Math.random() * 9) - 4;
        const target = block.offset({ x, y, z });
        if (target && target.isValid()) { //&& target.hasTag(McTags.Crops)
            if (growCrop(target)) {
                block.dimension.spawnParticle(McParticles.BoneMeal, target.center());
            }
        }
    }
    if (true) {
        //particles
        //spawn water drop particles in a circle randomly at a set angle from 30 to 40 degrees
        const molang = new MolangVariableMap();
        const speed = random(4.5, 5); // Set your desired speed here
        molang.setFloat("variable.spread", 0.5);
        molang.setFloat("variable.particle_initial_speed", speed);
        block.dimension.spawnParticle(SuppParticles.WaterSprinkle, block.center(), molang);
    }
}
export const FaucetTickComponent = {
    onTick(event) {
        const block = event.block;
        if (worldProxy.getTickTime() % 20 != 0)
            return;
        const power = block.getRedstonePower() | 0;
        const powered = power > 0;
        const activated = block.permutation.getState(SuppStates.Toggled);
        if (activated !== powered) {
            const dir = getADirection(block);
            const inFront = isAxisVertical(dir) ?
                offsetPos(block, dir) : block.below();
            const behind = offsetPos(block, flipDir(dir));
            if (inFront) {
                if (behind) {
                    if (inFront.isAir) {
                        if (dir == Direction.Up) {
                            sprinkleAround(block, behind);
                        }
                    }
                    else {
                        transferLiquids(behind, inFront);
                    }
                }
            }
            if (behind) {
                extractFromContainer(block, behind, dir);
            }
        }
    },
};
export const FaucetInteractComponent = {
    onPlayerInteract(event) {
        let block = event.block;
        let toggled = block.permutation.getState(SuppStates.Toggled);
        block.setPermutation(block.permutation.withState(SuppStates.Toggled, !toggled));
        const opt = { pitch: toggled ? 0.9 : 1.1, volume: 1 };
        event.dimension.playSound("razz_sup.faucet.squeak", block.center(), opt);
    }
};
function growCrop(block) {
    const id = block.typeId;
    if (id == McBlocks.Wheat || id == McBlocks.Carrots || id == McBlocks.Potatoes ||
        id == McBlocks.PumpkinStem || id == McBlocks.MelonStem) {
        const growth = block.permutation.getState(McStates.Growth);
        if (growth < 7) {
            block.west();
            block.setPermutation(block.permutation.withState(McStates.Growth, growth + 1));
            return true;
        }
    }
    else if (id == McBlocks.PitcherCrop) {
        const growth = block.permutation.getState(McStates.Growth);
        const upper = block.permutation.getState(McStates.UpperBlock);
        if (growth < 4 && !upper) {
            if (growth >= 2) {
                let aboveBlock = block.above();
                if (aboveBlock && (aboveBlock.isAir || aboveBlock.typeId == McBlocks.PitcherCrop)) {
                    block.setPermutation(block.permutation.withState(McStates.Growth, growth + 1));
                    aboveBlock.setPermutation(BlockPermutation.resolve(McBlocks.PitcherCrop)
                        .withState(McStates.Growth, growth + 1)
                        .withState(McStates.UpperBlock, true));
                    return true;
                }
                else
                    return false;
            }
            else {
                block.setPermutation(block.permutation.withState(McStates.Growth, growth + 1));
                return true;
            }
        }
    }
    else if (id == "razz_sup:flax_crop" /* SuppBlocks.Flax */) {
        const growth = block.permutation.getState(SuppStates.Growth);
        if (growth < 7) {
            block.setPermutation(block.permutation.withState(SuppStates.Growth, growth + 1));
            return true;
        }
    }
    else if (id == McBlocks.CocoaBeans) {
        const growth = block.permutation.getState(McStates.Age);
        if (growth < 2) {
            block.setPermutation(block.permutation.withState(McStates.Age, growth + 1));
            return true;
        }
    }
    else if (id == McBlocks.CaveVines || id == McBlocks.CaveVinesHead) {
        if (Math.random() < 0.3) {
            if (id == McBlocks.CaveVines) {
                block.setPermutation(BlockPermutation.resolve(McBlocks.CaveVinesBerries));
            }
            else {
                block.setPermutation(BlockPermutation.resolve(McBlocks.CaveVinesHeadBerries));
            }
            return true;
        }
    }
    return false;
    //TODO: test better and add more
}
function transferLiquids(behind, inFront) {
    const id = behind.typeId;
    if (hasWater(behind)) {
        if (fillWithWater(inFront)) {
        }
    }
    else if (id == McBlocks.WetSponge) {
        if (fillWithWater(inFront)) {
            behind.setType(McBlocks.Sponge);
        }
    }
    else if (id == "razz_sup:pumice" /* SuppBlocks.Pumice */) {
        if (fillWithLava(inFront, 3, 3)) {
            behind.setType("razz_sup:scorching_pumice" /* SuppBlocks.LavaPumice */);
        }
    }
    else if (id == McBlocks.Cauldron) {
        const liquid = behind.permutation.getState(McStates.CauldronLiquid);
        const fillLevel = behind.permutation.getState(McStates.FillLevel);
        if (liquid == "water" && fillLevel >= 2) {
            if (fillWithWater(inFront)) {
                behind.setPermutation(behind.permutation
                    .withState(McStates.FillLevel, fillLevel - 2));
            }
        }
        else if (liquid == "lava" && fillLevel == 6) {
            if (fillWithLava(inFront, 3, 3) == 3) {
                behind.setType(McBlocks.Air);
            }
        }
    }
    else if (id == McBlocks.Lava) {
        if (fillWithLava(inFront, 3, 3)) {
            behind.setType(McBlocks.Air);
        }
    }
    else if (id == "razz_sup:milk_cauldron" /* SuppBlocks.MilkCauldron */) {
        if (fillWithMilk(inFront)) {
            behind.setType(McBlocks.Cauldron);
        }
    }
    else if (id == McBlocks.Beehive || id == McBlocks.BeeNest) {
        const honeyLevel = behind.permutation.getState(McStates.HoneyLevel);
        if (honeyLevel == 5 && fillWithHoney(inFront)) {
            behind.setPermutation(behind.permutation.withState(McStates.HoneyLevel, 0));
        }
    }
    else if (id == "razz_sup:jar" /* SuppBlocks.Jar */) {
        const fillingType = getJarFillingType(behind.permutation);
        if (fillingType == FillingType.Water) {
            if (fillWithWater(inFront)) {
                tryTransferJarContent(behind, FillingType.Water, -1);
            }
        }
        else if (fillingType == FillingType.Honey) {
            if (fillWithHoney(inFront)) {
                tryTransferJarContent(behind, FillingType.Honey, -3);
            }
        }
        else if (fillingType == FillingType.Milk) {
            if (fillWithMilk(inFront)) {
                tryTransferJarContent(behind, FillingType.Milk, -3);
            }
        }
        if (fillingType == FillingType.Chocolate) {
            if (fillWithChocolate(inFront)) {
                tryTransferJarContent(behind, FillingType.Chocolate, -3);
            }
        }
        if (fillingType == FillingType.Lava) {
            let transferred = fillWithLava(inFront, 1, getJarVolume(behind.permutation));
            if (transferred != 0) {
                tryTransferJarContent(behind, FillingType.Lava, -transferred);
            }
        }
    }
}
function fillWithHoney(inFront) {
    if (inFront.typeId == McBlocks.Beehive || inFront.typeId == McBlocks.BeeNest) {
        const honeyLevel = inFront.permutation.getState(McStates.HoneyLevel);
        if (honeyLevel == 0) {
            inFront.setPermutation(inFront.permutation.withState(McStates.HoneyLevel, 5));
            return true;
        }
    }
    else if (inFront.typeId == "razz_sup:jar" /* SuppBlocks.Jar */) {
        if (tryTransferJarContent(inFront, FillingType.Honey, 1)) {
            return true;
        }
    }
    return false;
}
function fillWithWater(inFront) {
    if (inFront.typeId == McBlocks.Cauldron) {
        const lev = inFront.permutation.getState(McStates.FillLevel);
        const liquid = inFront.permutation.getState(McStates.CauldronLiquid);
        if (lev == 0 || (lev <= 4 && liquid == "water")) {
            inFront.setPermutation(inFront.permutation
                .withState(McStates.FillLevel, lev + 2)
                .withState(McStates.CauldronLiquid, "water"));
            return true;
        }
    }
    else if (inFront.typeId == "razz_sup:jar" /* SuppBlocks.Jar */) {
        if (tryTransferJarContent(inFront, FillingType.Water, 1)) {
            return true;
        }
    }
    return false;
}
//only one that could need to transfer more than 1 at a time
function fillWithLava(inFront, minAmount, maxAmount) {
    if (inFront.typeId == McBlocks.Cauldron && inFront.permutation.getState(McStates.FillLevel) == 0
        && maxAmount >= 3) {
        inFront.setPermutation(inFront.permutation
            .withState(McStates.FillLevel, 6)
            .withState(McStates.CauldronLiquid, "lava"));
        return 3;
    }
    else if (inFront.typeId == "razz_sup:jar" /* SuppBlocks.Jar */) {
        if (tryTransferJarContent(inFront, FillingType.Lava, minAmount)) {
            return minAmount;
        }
    }
    return 0;
}
function fillWithChocolate(inFront) {
    if (inFront.typeId == "razz_sup:jar" /* SuppBlocks.Jar */) {
        if (tryTransferJarContent(inFront, FillingType.Chocolate, 3)) {
            return true;
        }
    }
}
function fillWithMilk(inFront) {
    if (inFront.typeId == "razz_sup:jar" /* SuppBlocks.Jar */) {
        if (tryTransferJarContent(inFront, FillingType.Milk, 3)) {
            return true;
        }
    }
    if (inFront.typeId == McBlocks.Cauldron && inFront.permutation.getState(McStates.FillLevel) == 0) {
        inFront.setType("razz_sup:milk_cauldron" /* SuppBlocks.MilkCauldron */);
        return true;
    }
}
