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

const FEEDER_RADIUS = 2.5;
const FEEDER_GROW_UP_CHANCE = {
    numerator: 1,
    denominator: 5
};
const FEED_COOLDOWN_ADULT = 180 * mc.TicksPerSecond;
const FEED_COOLDOWN_BABY = 60 * mc.TicksPerSecond;

export const feederBlocks = [
    {
        ID: "sgs_farm:fun_feeder_large",
        entity: "sgs_farm:fun_feeder_large_inventory",
        maxFill: 16,
        families: [
            "cow",
            "goat",
            "sheep"
        ],
        tag: "sgs_farm_livestock_feed",
        viableItems: [
            "sgs_farm:maize_crop",
            "sgs_farm:rye_crop",
            "sgs_farm:sweetcorn_crop",
            "minecraft:wheat",
            "minecraft:carrot",
            "minecraft:potato",
            "sgs_farm:turnip_crop"
        ]
    },
    {
        ID: "sgs_farm:fun_feeder_pig",
        entity: "sgs_farm:fun_feeder_pig_inventory",
        maxFill: 8,
        component: "minecraft:compostable",
        tag: "sgs_farm_compostable",
        families: [
            "pig"
        ],
        viableItems: [
            "sgs_farm:maize_crop",
            "minecraft:wheat"
        ]
    },
    {
        ID: "sgs_farm:fun_feeder_poultry",
        entity: "sgs_farm:fun_feeder_poultry_inventory",
        maxFill: 8,
        tag: "sgs_farm_seed",
        families: [
            "chicken",
            "duck",
            "turkey"
        ],
        viableItems: [
            "minecraft:wheat_seeds",
            "minecraft:melon_seeds",
            "minecraft:pumpkin_seeds",
            "minecraft:beetroot_seeds",
            "minecraft:torchflower_seeds",
            "sgs_farm:wild_seed"
        ]
    },
    {
        ID: "sgs_farm:fun_feeder_rabbit",
        entity: "sgs_farm:fun_feeder_rabbit_inventory",
        maxFill: 8,
        tag: "sgs_farm_leafy_feed",
        families: [
            "rabbit"
        ],
        viableItems: [
            "sgs_farm:cabbage_green_crop",
            "sgs_farm:cabbage_red_crop",
            "sgs_farm:lettuce_crop",
            "sgs_farm:pak_choi_crop",
            "sgs_farm:turnip_crop",
            "sgs_farm:leeks_crop",
            "sgs_farm:spinach_crop",
            "minecraft:carrot",
            "minecraft:golden_carrot",
            "minecraft:dandelion",
            "sgs_farm:maize_crop",
            "minecraft:wheat"
        ]
    },

    //iron
    {
        ID: "sgs_farm:fun_feeder_large_iron",
        entity: "sgs_farm:fun_feeder_large_inventory",
        maxFill: 16,
        families: [
            "cow",
            "goat",
            "sheep"
        ],
        tag: "sgs_farm_livestock_feed",
        viableItems: [
            "sgs_farm:maize_crop",
            "sgs_farm:rye_crop",
            "sgs_farm:sweetcorn_crop",
            "minecraft:wheat",
            "minecraft:carrot",
            "minecraft:potato",
            "sgs_farm:turnip_crop"
        ]
    },
    {
        ID: "sgs_farm:fun_feeder_pig_iron",
        entity: "sgs_farm:fun_feeder_pig_inventory",
        maxFill: 8,
        component: "minecraft:compostable",
        tag: "sgs_farm_compostable",
        families: [
            "pig"
        ],
        viableItems: [
            "sgs_farm:maize_crop",
            "minecraft:wheat"
        ]
    },
    {
        ID: "sgs_farm:fun_feeder_poultry_iron",
        entity: "sgs_farm:fun_feeder_poultry_inventory",
        maxFill: 8,
        tag: "sgs_farm_seed",
        families: [
            "chicken",
            "duck",
            "turkey"
        ],
        viableItems: [
            "minecraft:wheat_seeds",
            "minecraft:melon_seeds",
            "minecraft:pumpkin_seeds",
            "minecraft:beetroot_seeds",
            "minecraft:torchflower_seeds",
            "sgs_farm:wild_seed"
        ]
    },
    {
        ID: "sgs_farm:fun_feeder_rabbit_iron",
        entity: "sgs_farm:fun_feeder_rabbit_inventory",
        maxFill: 8,
        tag: "sgs_farm_leafy_feed",
        families: [
            "rabbit"
        ],
        viableItems: [
            "sgs_farm:cabbage_green_crop",
            "sgs_farm:cabbage_red_crop",
            "sgs_farm:lettuce_crop",
            "sgs_farm:pak_choi_crop",
            "sgs_farm:turnip_crop",
            "sgs_farm:leeks_crop",
            "sgs_farm:spinach_crop",
            "minecraft:carrot",
            "minecraft:golden_carrot",
            "minecraft:dandelion",
            "sgs_farm:maize_crop",
            "minecraft:wheat"
        ]
    }
]

mc.system.afterEvents.scriptEventReceive.subscribe((eventData) => {
    const { id, sourceEntity, message } = eventData;
    if (sourceEntity == undefined) return;

    if (id == "sgs_farm:feeder_activate" && message == "large") {     //try to feed one viable animal nearby when feeder is stocked

        const location = sourceEntity.location;
        const dimension = sourceEntity.dimension.id;

        const currentFill = sourceEntity.getProperty("sgs_farm:fill");  //do we have food?
        if (currentFill <= 0) return;

        const time = mc.world.getAbsoluteTime();

        for (let entity of targetFamilies(location, dimension, FEEDER_RADIUS, feederBlocks[0].families)) {
            if (feedAnimal(entity, time)) {
                //break function on first successful feed attempt
                try {
                    entity.triggerEvent("minecraft:on_eat_block");    //try regrow sheep wool when fed
                } catch (error) { }
                sourceEntity.setProperty("sgs_farm:fill", currentFill - 1);
                sourceEntity.dimension.playSound("dig.grass", sourceEntity.location);
                sourceEntity.dimension.spawnParticle("sgs_farm:feeder_hay", sourceEntity.location);
                return;
            }
        }
        return;
    };

    if (id == "sgs_farm:feeder_activate" && message == "pig") {     //try to feed one viable animal nearby when feeder is stocked

        const location = sourceEntity.location;
        const dimension = sourceEntity.dimension.id;

        const currentFill = sourceEntity.getProperty("sgs_farm:fill");  //do we have food?
        if (currentFill <= 0) return;

        const time = mc.world.getAbsoluteTime();

        for (let entity of targetFamilies(location, dimension, FEEDER_RADIUS, feederBlocks[1].families)) {
            if (feedAnimal(entity, time)) {
                //break function on first successful feed attempt
                sourceEntity.setProperty("sgs_farm:fill", currentFill - 1);
                sourceEntity.dimension.playSound("dig.grass", sourceEntity.location);
                sourceEntity.dimension.spawnParticle("sgs_farm:feeder_hay", sourceEntity.location);
                return;
            }
        }
        return;
    };

    if (id == "sgs_farm:feeder_activate" && message == "poultry") {     //try to feed one viable animal nearby when feeder is stocked

        const location = sourceEntity.location;
        const dimension = sourceEntity.dimension.id;

        const currentFill = sourceEntity.getProperty("sgs_farm:fill");  //do we have food?
        if (currentFill <= 0) return;

        const time = mc.world.getAbsoluteTime();

        for (let entity of targetFamilies(location, dimension, FEEDER_RADIUS, feederBlocks[2].families)) {
            if (feedAnimal(entity, time)) {
                //break function on first successful feed attempt
                sourceEntity.setProperty("sgs_farm:fill", currentFill - 1);
                sourceEntity.dimension.playSound("dig.grass", sourceEntity.location);
                sourceEntity.dimension.spawnParticle("sgs_farm:feeder_hay", sourceEntity.location);
                return;
            }
        }
        return;
    };

    if (id == "sgs_farm:feeder_activate" && message == "rabbit") {     //try to feed one viable animal nearby when feeder is stocked

        const location = sourceEntity.location;
        const dimension = sourceEntity.dimension.id;

        const currentFill = sourceEntity.getProperty("sgs_farm:fill");  //do we have food?
        if (currentFill <= 0) return;

        const time = mc.world.getAbsoluteTime();

        for (let entity of targetFamilies(location, dimension, FEEDER_RADIUS, feederBlocks[3].families)) {
            if (feedAnimal(entity, time)) {
                //break function on first successful feed attempt
                sourceEntity.setProperty("sgs_farm:fill", currentFill - 1);
                sourceEntity.dimension.playSound("dig.grass", sourceEntity.location);
                sourceEntity.dimension.spawnParticle("sgs_farm:feeder_hay", sourceEntity.location);
                return;
            }
        }
        return;
    };
})

function feedAnimal(entity, time) {
    let entityFeedTime = parseInt(entity.getDynamicProperty("sgs_farm_feedtime"));  //get last feed timestamp
    if (isNaN(entityFeedTime)) entityFeedTime = time;

    if ((entityFeedTime - time) > 0) return false;

    const ageable = entity.getComponent('minecraft:ageable');
    if (ageable == undefined) {
        //adult mob
        if (!entity.typeId.startsWith("sgs_farm")) return false;    //adult mob functionality only applies to crops & farms mobs
        if (entity.getProperty("sgs_farm:sleeping")) return false;  //don't feed sleeping entities, wtf

        entity.setDynamicProperty("sgs_farm_feedtime", time + FEED_COOLDOWN_ADULT);  //set our feeding timestamp + cooldown
        entity.triggerEvent("evt:well_fed");    //set our entity as well fed
        entity.playAnimation("eat");
        return true;
    }
    else {
        //baby mob
        entity.setDynamicProperty("sgs_farm_feedtime", time + FEED_COOLDOWN_BABY);

        const num = randomNum(0, FEEDER_GROW_UP_CHANCE.denominator);
        if (num > FEEDER_GROW_UP_CHANCE.numerator) return false;

        entity.triggerEvent(ageable.growUp.eventName);  //grow up baby entity
        entity.dimension.spawnParticle("minecraft:crop_growth_emitter", entity.location);
        entity.playAnimation("eat");
        entity.setDynamicProperty("sgs_farm_feedtime", time + FEED_COOLDOWN_ADULT);
        return true;
    }
}



export class feederManager {
    static beforeplace(data) {
        const block = data.block;
        const blockId = data.permutationToPlace.type.id;

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

        const northConnects = (north.hasTag("sgs_farm_feeder") && north.type.id == blockId);
        const eastConnects = (east.hasTag("sgs_farm_feeder") && east.type.id == blockId);
        const southConnects = (south.hasTag("sgs_farm_feeder") && south.type.id == blockId);
        const westConnects = (west.hasTag("sgs_farm_feeder") && west.type.id == blockId);

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

        mc.system.runTimeout(() => {
            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));

            const blockdata = feederBlocks.find((f) => f.ID == blockId);
            mc.world.getDimension(block.dimension.id).spawnEntity(blockdata.entity, block.bottomCenter());
        }, 0)
    }

    static destroy(data) {

        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 blockId = data.destroyedBlockPermutation.type.id;

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

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

        const location = block.bottomCenter();
        mc.world.getDimension(block.dimension.id).getEntities({ location, families: ["sgs_farm_feeder"], maxDistance: 0.2 })[0].remove();
    }

    static beforeplace_cardinal(data) {
        const block = data.block;
        const blockId = data.permutationToPlace.type.id;

        mc.system.runTimeout(() => {
            const blockdata = feederBlocks.find((f) => f.ID == blockId);
            const entity = mc.world.getDimension(block.dimension.id).spawnEntity(blockdata.entity, block.bottomCenter());
            const direction = data.permutationToPlace.getState("minecraft:cardinal_direction");
            switch (direction) {
                case "north":
                    entity.setProperty("sgs_farm:rotation", 2);
                    break;
                case "east":
                    entity.setProperty("sgs_farm:rotation", 3);
                    break;
                case "south":
                    entity.setProperty("sgs_farm:rotation", 0);
                    break;
                case "west":
                    entity.setProperty("sgs_farm:rotation", 1);
                    break;
                default:
                    break;
            }
        }, 0)
    }

    static destroy_cardinal(data) {
        const block = data.block;
        const location = block.bottomCenter();
        mc.world.getDimension(block.dimension.id).getEntities({ location, families: ["sgs_farm_feeder"], maxDistance: 0.2 })[0].remove();
    }

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

        const blockdata = feederBlocks.find((f) => f.ID == block.type.id);  //check if we even have a feeder block
        if (blockdata == undefined) return;

        const block_entity = this.getBlockEntity(block); //check if we have a block entity
        if (block_entity == undefined) return;

        //run info message regardless of outcome with delay
        mc.system.runTimeout(() => {
            player.onScreenDisplay.setActionBar("Feed: " + block_entity.getProperty("sgs_farm:fill") + "/" + blockdata.maxFill);
        }, 2)

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

        if (blockdata.ID == "sgs_farm:fun_feeder_pig" || blockdata.ID == "sgs_farm:fun_feeder_pig_iron") {
            const compostable = heldItem.getComponent("minecraft:compostable");
            if (compostable == undefined) return;

            let currentFill = block_entity.getProperty("sgs_farm:fill");
            if (currentFill >= blockdata.maxFill) return;
            const fillDiff = blockdata.maxFill - currentFill;

            let fillAmount = fillDiff;
            if (heldItem.amount < fillDiff) fillAmount = heldItem.amount;

            player.dimension.playSound("block.composter.fill", block.location);
            block_entity.setProperty("sgs_farm:fill", currentFill + fillAmount);

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

        if (blockdata.ID == "sgs_farm:fun_feeder_poultry" || blockdata.ID == "sgs_farm:fun_feeder_poultry_iron") {

            if (!heldItem.hasTag("sgs_farm:seed") && !blockdata.viableItems.includes(heldItem.typeId)) return;

            let currentFill = block_entity.getProperty("sgs_farm:fill");
            if (currentFill >= blockdata.maxFill) return;
            const fillDiff = blockdata.maxFill - currentFill;

            let fillAmount = fillDiff;
            if (heldItem.amount < fillDiff) fillAmount = heldItem.amount;

            player.dimension.playSound("block.composter.fill", block.location);
            block_entity.setProperty("sgs_farm:fill", currentFill + fillAmount);

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

        if (blockdata.viableItems.includes(heldItem.typeId)) //got the right thing in hand?
        {
            let currentFill = block_entity.getProperty("sgs_farm:fill");
            if (currentFill >= blockdata.maxFill) return;
            const fillDiff = blockdata.maxFill - currentFill;

            let fillAmount = fillDiff;
            if (heldItem.amount < fillDiff) fillAmount = heldItem.amount;

            player.dimension.playSound("block.composter.fill", block.location);
            block_entity.setProperty("sgs_farm:fill", currentFill + fillAmount);

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

    static getBlockEntity(block) {
        const location = block.bottomCenter();
        return mc.world.getDimension(block.dimension.id).getEntities({ location, families: ["sgs_farm_feeder"], maxDistance: 0.2 })[0];
    }
}
