import { world, system, ItemStack, EnchantmentType } from "@minecraft/server";
import * as utils from "../utils";
import * as inventory_utils from "../inventory_utils";

export const DELIVERY_TYPE = {
    food: "food",
    gear: "gear",
    enchantment: "enchantment",
    building: "building",
};

export const DELIVERY_TYPE_COLOR = {
    food: "§a",
    gear: "§1",
    enchantment: "§5",
    building: "§3",
};

const DELIVERY_TIME = 5; // seconds

const MAX_DELIVERIES = 20;


export async function sendDelivery(player, deliveryType, typeId, itemName, amount) {
    utils.tellraw(player, "@s", `The Item will be delivered in a few seconds.`);
    for (let i = 1; i <= MAX_DELIVERIES; i++) {
        if (player.getDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_type`) !== undefined)
            continue;

        // Slot is free
        player.setDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_type`, deliveryType);  // Save delivery type
        player.setDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_typeId`, typeId);      // Save delivery item
        player.setDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_name`, itemName);      // Save delivery item
        player.setDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_amount`, amount);      // Save delivery item
        player.setDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_time`, DELIVERY_TIME); // Save time
        break;
    }
}

export async function onTick() {
    for (const player of world.getAllPlayers()) {
        updateDelivery(player);
    }
}

async function updateDelivery(player) {
    for (const deliveryType of Object.values(DELIVERY_TYPE)) {
        let deliveriesCount = 0;
        for (let i = 1; i <= MAX_DELIVERIES; i++) {
            if (player.getDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_type`) === undefined)
                continue;
    
            // Slot has delivery
            let timeLeft = player.getDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_time`) - 1; // Load and decrement time
            if (timeLeft === 0) {           
                // Give player delivery
                const itemType = player.getDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_typeId`);
                const itemName = player.getDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_name`);
                const itemAmount = player.getDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_amount`);

                // Clear slot
                player.setDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_type`, undefined);   // Save delivery type
                player.setDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_typeId`, undefined); // Save delivery item
                player.setDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_name`, undefined);   // Save delivery item
                player.setDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_amount`, undefined); // Save delivery item
                player.setDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_time`, undefined);   // Save time

                player.playSound("goe_spa:delivery");
                utils.runPlayerCommand(player, "particle goe_spa:delivery");

                // Create item
                let suffix = ""
                if (deliveryType !== DELIVERY_TYPE.enchantment) {
                    if (itemType !== "minecraft:arrow")
                        suffix = "x" + itemAmount;
                } else {
                    suffix = utils.toRoman(itemAmount)
                }

                const packageItem = new ItemStack("goe_spa:delivery_package", 1);
                packageItem.nameTag = `§cDelivery Package §7(Interact to open)\n§fContent: ${itemName} ${suffix}`;
                packageItem.setDynamicProperty("goe_spa_package_type", deliveryType);
                packageItem.setDynamicProperty("goe_spa_package_typeId", itemType);
                packageItem.setDynamicProperty("goe_spa_package_name", itemName);
                packageItem.setDynamicProperty("goe_spa_package_amount", itemAmount);

                // Give player
                player.dimension.spawnItem(packageItem, player.location);

                utils.tellraw(player, "@s", `You received a new delivery!`);                
                continue;
            }

            ++deliveriesCount;

            player.setDynamicProperty(`goe_spa_${deliveryType}_delivery_${i}_time`, timeLeft);
        }       
    }
}

export async function onItemUse(event) {
    const player = event.source;
    const packageItem = event.itemStack;

    await inventory_utils.removeItemInHand(player);

    const deliveryType = packageItem.getDynamicProperty("goe_spa_package_type");
    const itemType = packageItem.getDynamicProperty("goe_spa_package_typeId");
    const itemName = packageItem.getDynamicProperty("goe_spa_package_name");
    const itemAmount = packageItem.getDynamicProperty("goe_spa_package_amount");
    
    if (deliveryType === DELIVERY_TYPE.enchantment)
        giveEnchantment(player, itemType, itemAmount);
    else
        giveItem(player, itemType, itemAmount);

    player.playSound("goe_spa:delivery_open");
    //player.playSound("goe_spa:open_package");
    utils.runPlayerCommand(player, "particle goe_spa:package_open");

    playerFireworks(player, {x: 1.5, y: 0.5, z: 2});
    system.runTimeout(() => playerFireworks(player, {x: -1.5, y: 0, z: 2}), 5);
    system.runTimeout(() => playerFireworks(player, {x: 1.5, y: 0, z: 2}), 10);
    system.runTimeout(() => playerFireworks(player, {x: -1.5, y: 0.5, z: 2}), 15);
}

export async function onScriptEventReceive(event) {
    const source = event.sourceEntity;

    if (event.message === "interact") {
        
        source.triggerEvent("goe_spa:despawn");
    } else if (event.message === "remove_name") {
        source.nameTag = "";
    }
}

function giveItem(player, itemType, amount) {
    const id = utils.toSnakeCase(itemType);
    const item = new ItemStack(itemType, amount);
    player.dimension.spawnItem(item, player.location);
}

function giveEnchantment(player, enchantmentType, level) {
    const book = new ItemStack("minecraft:enchanted_book", 1);
    const enchantments = book?.getComponent("minecraft:enchantable");
    enchantments.addEnchantment({
        type: new EnchantmentType(enchantmentType),
        level: level
    });

    player.dimension.spawnItem(book, player.location);
}

async function playerFireworks(player, offset) {
    utils.runPlayerCommand(player, `particle goe_spa:fireworks ^${offset.x} ^${offset.y} ^${offset.z}`);
}