import { world, BlockPermutation, StructureAnimationMode, StructureRotation } from '@minecraft/server';
import { getBiomelessBlockTransformation } from '../transformations/index';
import NoiseMap3D from '../noise';
import WBVector3 from '../../util/wbVector3';
import { Chunk3Utils } from '../../util/chunk';
import { getRandomChoice, mulberryPRNG } from '../../util/random';
import { landAshOnBlock } from '../../blocks/ash';
export const ASH_PATCH_NOISE = new NoiseMap3D(12345, 10, 0.3);
export const SOUL_PATCH_NOISE = new NoiseMap3D(45678, 12.5, 0.7);
export const WILT_PATCH_NOISE = new NoiseMap3D(13579, 5, [0.5, 0.1, -0.3]);
const TREE_CHUNK_SIZE = 10;
const TREE_CHUNK_CHANCE = 0.5;
const TREE_CHUNK_MAX_OFFSET = 4;
const DESERT_SOUL_SAND_FIRE_CHANCE = 0.01;
const MANGROVE_TREE_TIP_CHANCE = 0.25;
const STRUCTURE_ROTATIONS = [
    StructureRotation.None,
    StructureRotation.Rotate90,
    StructureRotation.Rotate180,
    StructureRotation.Rotate270,
];
export const SMALL_TREE_STRUCTURES = [
    world.structureManager.get('twb_wisu/tree1'),
    world.structureManager.get('twb_wisu/tree2'),
    world.structureManager.get('twb_wisu/tree3'),
    world.structureManager.get('twb_wisu/tree4'),
    world.structureManager.get('twb_wisu/tree5'),
    world.structureManager.get('twb_wisu/tree6'),
];
export const LARGE_TREE_STRUCTURES = [
    world.structureManager.get('twb_wisu/tree1_large'),
    world.structureManager.get('twb_wisu/tree2_large'),
    world.structureManager.get('twb_wisu/tree3_large'),
    world.structureManager.get('twb_wisu/tree4_large'),
    world.structureManager.get('twb_wisu/tree5_large'),
];
export function isInAshPatch(block) {
    if (!block || !block.isValid())
        return false;
    return ASH_PATCH_NOISE.query(block);
}
export function isInSoulPatch(block) {
    if (!block || !block.isValid())
        return false;
    return SOUL_PATCH_NOISE.query(block);
}
export function isInWiltPatch(block, threshold = 0) {
    if (!block || !block.isValid())
        return false;
    return WILT_PATCH_NOISE.query(block, threshold);
}
export function convertBlockAboveGrass(block) {
    const above = block.above();
    if (!above || !above.isValid())
        return;
    getBiomelessBlockTransformation(above.typeId)?.transform(above);
}
export function convertBlockAboveNonRepeat(block, oldPermutation) {
    const above = block.above();
    if (!above || !above.isValid() || oldPermutation.matches(above.typeId))
        return;
    getBiomelessBlockTransformation(above.typeId)?.transform(above);
}
export function placeTallWilt(block, threshold = 0) {
    const above = block.above();
    if (isInWiltPatch(above, threshold)) {
        getBiomelessBlockTransformation(above.typeId)?.transform(above);
        if (above.isAir)
            above.setType('twb_wisu:wilt');
    }
}
export function placeSoulFire(block) {
    if (Math.random() < DESERT_SOUL_SAND_FIRE_CHANCE) {
        const above = block.above();
        if (above?.isValid() && above.isAir) {
            above.setType('minecraft:soul_fire');
        }
    }
}
const treeChunks = new Chunk3Utils(TREE_CHUNK_SIZE);
export function shouldSpawnTree(loc) {
    const chunk = treeChunks.toChunkSpace(loc).floorAll();
    const rand = mulberryPRNG(chunk.x * 12345 + chunk.z * 32894);
    if (rand() > TREE_CHUNK_CHANCE)
        return false;
    const center = treeChunks.getChunkCenter(chunk);
    const offsetX = Math.floor((rand() * 2 - 1) * TREE_CHUNK_MAX_OFFSET + center.x);
    const offsetZ = Math.floor((rand() * 2 - 1) * TREE_CHUNK_MAX_OFFSET + center.z);
    return (offsetX === loc.x && offsetZ === loc.z);
}
export function transformLogBlock(value) {
    const state = 'minecraft:block_face';
    switch (value) {
        case 'x':
            return { state, value: 'east' };
        case 'y':
            return { state, value: 'up' };
        case 'z':
            return { state, value: 'north' };
        default:
            return { state, value: 'up' };
    }
}
export function destroySnowLayer(block) {
    const above = block.above();
    if (above?.isValid() && above.permutation.matches('minecraft:snow_layer')) {
        above.setType('minecraft:air');
    }
}
export function replaceDirtBelow(block) {
    const below = block.below();
    if (below
        && (below.permutation.matches('minecraft:dirt')
            || below.permutation.matches('minecraft:soul_soil'))) {
        getBiomelessBlockTransformation('minecraft:grass_block').transform(below);
    }
}
export function destroyAttachedVines(block) {
    const blocks = [block.north(), block.east(), block.south(), block.west()];
    blocks.forEach((side) => {
        if (side?.permutation.matches('minecraft:vine')) {
            getBiomelessBlockTransformation('minecraft:vine').transform(side);
        }
    });
}
export function destroyAttachedCocoa(block) {
    const blocks = [block.north(), block.east(), block.south(), block.west()];
    blocks.forEach((side) => {
        if (side?.permutation.matches('minecraft:cocoa')) {
            getBiomelessBlockTransformation('minecraft:cocoa').transform(side);
        }
    });
}
export function destroyHangingPropagule(block) {
    const below = block.below();
    if (below?.permutation.matches('minecraft:mangrove_propagule')) {
        getBiomelessBlockTransformation(below.typeId).transform(below);
    }
}
export function destroyHangingMoss(block) {
    const below = block.below();
    if (below?.permutation.matches('minecraft:pale_hanging_moss')) {
        getBiomelessBlockTransformation(below.typeId).transform(below);
    }
}
export function destroyTallPlant(block, oldPermutation) {
    const above = block.above();
    if (above) {
        if (oldPermutation.matches(above.typeId)) {
            above.setType('minecraft:air');
        }
    }
}
export function destroyRisingPlant(block) {
    const above = block.above();
    if (above?.permutation.matches(block.typeId)) {
        getBiomelessBlockTransformation(above.typeId)?.transform(above);
    }
}
export function destroyRisingPlantBidirectional(block, oldPermutation) {
    const above = block.above();
    if (above && oldPermutation.matches(above.typeId)) {
        getBiomelessBlockTransformation(above.typeId)?.transform(above);
    }
    const below = block.below();
    if (below && oldPermutation.matches(below.typeId)) {
        getBiomelessBlockTransformation(below.typeId)?.transform(below);
    }
}
export function destroyHangingPlant(block) {
    const below = block.below();
    if (below?.permutation.matches(block.typeId)) {
        getBiomelessBlockTransformation(below.typeId)?.transform(below);
    }
}
function placeStructure(block, offset, structures) {
    const structure = getRandomChoice(structures);
    world.structureManager.place(structure, block.dimension, offset.add(block), {
        animationMode: StructureAnimationMode.Blocks,
        animationSeconds: 1.0,
        rotation: getRandomChoice(STRUCTURE_ROTATIONS)
    });
}
function destroyNearbyBamboo(block) {
    // Destroy bamboo
    const above = block.above()?.above();
    if (above?.isValid()) {
        const blocks = [
            above,
            above.north(), above.east(), above.south(), above.west(),
            above.north()?.east(), above.north()?.west(),
            above.south()?.east(), above.south()?.west(),
        ];
        const transformation = getBiomelessBlockTransformation('minecraft:bamboo');
        blocks.forEach((side) => {
            if (side?.isValid() && side.permutation.matches('minecraft:bamboo')) {
                transformation.transform(side);
            }
        });
    }
}
export function generateSmallTree(block) {
    if (!shouldSpawnTree(block)) {
        convertBlockAboveGrass(block);
        return;
    }
    destroyNearbyBamboo(block);
    placeStructure(block, new WBVector3(0, -1, 0), SMALL_TREE_STRUCTURES);
}
export function generateLargeTree(block) {
    if (!shouldSpawnTree(block)) {
        convertBlockAboveGrass(block);
        return;
    }
    // Destroy bamboo
    const above = block.above();
    if (above?.isValid()) {
        const blocks = [
            above,
            above.north(), above.east(), above.south(), above.west(),
            above.north()?.east(), above.north()?.west(),
            above.south()?.east(), above.south()?.west(),
        ];
        blocks.forEach((side) => {
            if (side?.isValid() && side.permutation.matches('minecraft:bamboo')) {
                getBiomelessBlockTransformation('minecraft:bamboo').transform(side);
            }
        });
    }
    placeStructure(block, new WBVector3(0, -1, 0), LARGE_TREE_STRUCTURES);
}
export function convertCactus(block) {
    const below = block.below();
    if (below?.isValid()) {
        getBiomelessBlockTransformation(below.typeId)?.transform(below);
    }
    const above = block.above();
    if (above?.permutation.matches('minecraft:cactus')) {
        getBiomelessBlockTransformation(above.typeId)?.transform(above);
    }
}
export function convertSeaGrass(block, oldPermutation) {
    const type = oldPermutation.getState('sea_grass_type');
    let nextBlock;
    if (type === 'double_bot') {
        nextBlock = block.above();
    }
    else if (type === 'double_top') {
        nextBlock = block.below();
    }
    if (nextBlock?.isValid() && !nextBlock.isAir) {
        getBiomelessBlockTransformation(nextBlock.typeId)?.transform(nextBlock);
    }
}
export function convertNeighbouringCacti(block) {
    const blocks = [block.north(), block.east(), block.south(), block.west()];
    blocks.forEach((side) => {
        if (side?.permutation.matches('minecraft:cactus')) {
            getBiomelessBlockTransformation('minecraft:cactus').transform(side);
        }
    });
}
export function convertBlockBelow(block) {
    const below = block.below();
    if (below?.isValid()) {
        getBiomelessBlockTransformation(below.typeId)?.transform(below);
    }
}
export function ashLayerToBlock(block) {
    const above = block.above();
    if (!above?.isAir) {
        block.setType('twb_wisu:ash');
    }
}
export function spreadAsh(block, replacesBlocks) {
    if (block.above()?.isAir && (block.north()?.isAir
        || block.east()?.isAir
        || block.south()?.isAir
        || block.west()?.isAir)) {
        block.setType('minecraft:air');
        landAshOnBlock(block, 8, { replacesBlocks, disableEntitySpawning: true });
    }
}
function isMangroveLog(block) {
    return (block === undefined
        || block.permutation.matches('minecraft:mangrove_log')
        || block.permutation.matches('twb_wisu:withered_log')
        || block.permutation.matches('twb_wisu:withered_soul_log'));
}
export function mangroveLogReplaceTips(block) {
    if (Math.random() > MANGROVE_TREE_TIP_CHANCE)
        return;
    const above = block.above();
    if (isMangroveLog(above))
        return;
    if (isMangroveLog(above.north()))
        return;
    if (isMangroveLog(above.east()))
        return;
    if (isMangroveLog(above.south()))
        return;
    if (isMangroveLog(above.west()))
        return;
    if (isMangroveLog(block.north()))
        return;
    if (isMangroveLog(block.east()))
        return;
    if (isMangroveLog(block.south()))
        return;
    if (isMangroveLog(block.west()))
        return;
    block.setPermutation(BlockPermutation.resolve('twb_wisu:withered_soul_log'));
}
export function afterConvertDoor(block) {
    const isUpper = !!block.permutation.getState('twb_wisu:upper_block_bit');
    const other = block.offset({ x: 0, y: isUpper ? -1 : 1, z: 0 });
    if (other?.isValid()) {
        getBiomelessBlockTransformation(other.typeId)?.transform(other);
    }
}
