import { CustomForm, FormButton, FormLabel, FormSlider, SimpleForm } from "bdsx/bds/form";
import { ServerPlayer } from "bdsx/bds/player";
import { ItemStack } from "bdsx/bds/inventory";
import { EconomyX } from "@bdsx/economy-x";
import { send, sendTranslate } from "./utils/translate";
import * as path from "path";
import * as fs from "fs";

export interface ShopItem {
    icon?: string;
    path?: "path"|"url";
    description?: string;
    item: keyof ItemIdMap;
    data?: number;
    price: number;
}

export interface CompoundShop {
    icon?: string;
    path?: "path"|"url";
    name: string;
    description?: string;
    category: Record<string, CompoundShop>;
}

const filePath = path.join(__dirname, "..", "shop.json");
let shop: {
    shopui: {
        title: string;
        description: string;
        buy_content: string[];
        buttons: {
            category: string;
            item: string;
        };
    };
    category: Record<string, CompoundShop>;
    items: Record<string, ShopItem[]>;
} = {
    shopui: {
        title: "§l§2ShopUI",
        description: "",
        buy_content: [
            "Money: §e%money%",
            "Item: §a%item%",
            "Price: §e%price%",
        ],
        buttons: {
            category: "§l%name%§r\n§8Click for more",
            item: "§a%name%§r\n§7Price: §e%price%",
        },
    },
    category: {
        blocks: {
            icon: "textures/blocks/cobblestone",
            path: "path",
            name: "§l§aBlocks",
            category: {},
        },
        foods: {
            icon: "textures/items/beef_cooked",
            path: "path",
            name: "§l§6Foods",
            category: {},
        },
        tools: {
            icon: "textures/items/diamond_sword",
            path: "path",
            name: "§l§dTools",
            category: {},
        },
    },
    items: {
        blocks: [
            {
                icon: "textures/blocks/grass_side_carried",
                path: "path",
                item: "minecraft:grass",
                price: 1.5,
            },
            {
                icon: "textures/blocks/dirt",
                path: "path",
                item: "minecraft:dirt",
                price: 0.7,
            },
            {
                icon: "textures/blocks/stone",
                path: "path",
                item: "minecraft:stone",
                price: 2,
            },
            {
                icon: "textures/blocks/cobblestone",
                path: "path",
                item: "minecraft:cobblestone",
                price: 1.3,
            },
        ],
        foods: [
            {
                icon: "textures/items/beef_cooked",
                path: "path",
                item: "minecraft:cooked_beef",
                price: 1.8,
            },
            {
                icon: "textures/items/beef_raw",
                path: "path",
                item: "minecraft:beef",
                price: 1.2,
            },
        ],
        tools: [
            {
                icon: "textures/items/iron_sword",
                path: "path",
                item: "minecraft:iron_sword",
                price: 8,
            },
            {
                icon: "textures/items/iron_axe",
                path: "path",
                item: "minecraft:iron_axe",
                price: 8.7,
            },
            {
                icon: "textures/items/iron_pickaxe",
                path: "path",
                item: "minecraft:iron_pickaxe",
                price: 8.7,
            },
        ],
    },
};
//Why are there so few items? Because i have very little time and you can customize it

try { shop = require(filePath) } catch(err) {}

export namespace ShopMain {
    export function buy(shopItem: ShopItem, amount: number, player: ServerPlayer): boolean {
        const xuid = player.getXuid();
        if (xuid === "") {
            player.sendMessage(send.text(`player.xuid.notfound`));
            return false;
        }
        if (amount < 1) {
            player.sendMessage(send.text(`player.invalid.amount`));
            return false;
        }

        const item = ItemStack.constructWith(shopItem.item, amount, shopItem.data);
        if (shopItem.price < 0||shopItem.price === 0) {
            player.sendMessage(send.text(`success.buy.freeitem`).replace(/%name%/g, item.getCustomName()).replace(/%amount%/g, `${amount}`));
            player.addItem(item);
            player.sendInventory();
            return true;
        }

        const total = amount*shopItem.price;
        if (EconomyX.getMoney(player)-total < 0) {
            player.sendMessage(send.text(`player.money.notenough`));
            return false;
        }

        player.sendMessage(send.text(`success.buy.item`).replace(/%name%/g, item.getCustomName()).replace(/%amount%/g, `${amount}`).replace(/%total%/g, `${EconomyX.currency() + total}`));
        EconomyX.removeMoney(player, total);
        player.addItem(item);
        player.sendInventory();
        return true;
    }

    export function getCategories(): string[] {
        return Object.keys(shop.category);
    }

    export function getCompound(category: string): CompoundShop|null {
        if (!shop.category.hasOwnProperty(category)) return null;
        return shop.category[category];
    }

    /**@deprecated */
    export function getCategoryFromPath(path: string): string[] {return []};
    /**@deprecated */
    export function getCompoundFromPath(path: string): CompoundShop|null {return null};

    export function getItemCategories(): string[] {
        return Object.keys(shop.items);
    }

    export function hasItemCategory(category: string): boolean {
        return shop.items.hasOwnProperty(category);
    }

    export function getItems(category: string): ShopItem[]|undefined {
        if (!shop.items.hasOwnProperty(category)) return undefined;
        else return shop.items[category];
    }

    export function getItem(category: string, item: keyof ItemIdMap): ShopItem|null {
        if (!shop.items.hasOwnProperty(category)) return null;

        const shopItem = shop.items[category].find((v) => item === v.item);
        if (!shopItem) return null;
        return shopItem;
    }

    export function createItemCategory(category: string, items: ShopItem[] = [], message: boolean = false, actor?: ServerPlayer): boolean {
        const sendT = new sendTranslate(actor, message);
        if (shop.items.hasOwnProperty(category)) {
            sendT.error(`category.already`);
            return false;
        }
        else {
            sendT.success(send.text(`category.created`).replace(/%category%/g, category));
            shop.items[category]=items;
            return true;
        }
    }

    export function deleteCategory(category: string, message: boolean = false, actor?: ServerPlayer): boolean {
        const sendT = new sendTranslate(actor, message);
        if (!shop.items.hasOwnProperty(category)) {
            sendT.error(`category.notfound`);
            return false;
        }
        else {
            sendT.success(send.text(`category.deleted`).replace(/%category%/g, category));
            delete shop.items[category];
            return true;
        }
    }

    export function addItem(category: string, item: keyof ItemIdMap, data: number = 0, price: number, description?: string, iconPath?: "path"|"url", icon?: string, message: boolean = false, actor?: ServerPlayer): boolean {
        const sendT = new sendTranslate(actor, message);
        if (!shop.items.hasOwnProperty(category)) {
            sendT.error(`category.notfound`);
            return false;
        }
        if (shop.items[category].find((v) => item === v.item)) {
            sendT.error(`item.already`);
            return false;
        }
        if (price < 0) {
            sendT.error(`item.invalid.price`);
            return false;
        }

        sendT.success(send.text(`item.added`).replace(/%item%/g, item).replace(/%category%/g, category).replace(/%price%/g, `${EconomyX.currency()}${price}`));
        shop.items[category].push({
            icon: icon,
            path: iconPath,
            description: description,
            item: item,
            data: data,
            price: price,
        });
        return true;
    }

    export function removeItem(category: string, item: keyof ItemIdMap, message: boolean = false, actor?: ServerPlayer): boolean {
        const sendT = new sendTranslate(actor, message);
        if (!shop.items.hasOwnProperty(category)) {
            sendT.error(`category.notfound`);
            return false;
        }
        if (!shop.items[category].find((v) => item === v.item)) {
            sendT.error(`item.notfound`);
            return false;
        }

        sendT.success(send.text(`item.removed`).replace(/%item%/g, item).replace(/%category%/g, category));
        shop.items[category]=shop.items[category].filter((v) => item !== v.item);
        return true;
    }

    export function setItem(category: string, item: keyof ItemIdMap, newItem: keyof ItemIdMap, data?: number, message: boolean = false, actor?: ServerPlayer): boolean {
        if (!shop.items.hasOwnProperty(category)) {
            send.error(`category.notfound`);
            return false;
        }

        const shopItem = shop.items[category].find((v) => item === v.item);
        if (!shopItem) {
            send.error(`item.notfound`);
            return false;
        }
        if (item === newItem && shopItem.data === data) {
            send.error(`item.same`);
            return false;
        }

        send.success(send.text(`item.seted`).replace(/%olditem%/g, item).replace(/%olddata%/g, `${shopItem.data ?? 0}`).replace(/%item%/g, newItem).replace(/%data%/g, `${data ?? 0}`).replace(/%category%/g, category));
        const index = shop.items[category].indexOf(shopItem);
        shop.items[category][index]={
            icon: shopItem.icon,
            path: shopItem.path,
            description: shopItem.description,
            item: newItem,
            data: data ?? shopItem.data,
            price: shopItem.price,
        };
        return true;
    }

    export function getPrice(category: string, item: keyof ItemIdMap): number|null {
        if (!shop.items.hasOwnProperty(category)) return null;
        const shopItem = shop.items[category].find((v) => item === v.item);
        if (!shopItem) return null;
        if (shopItem.price < 0) return 0;
        return shopItem.price;
    }

    export function setPrice(category: string, item: keyof ItemIdMap, price: number, message: boolean = false, actor?: ServerPlayer): boolean {
        const sendT = new sendTranslate(actor, message);
        if (shop.items.hasOwnProperty(category)) {
            sendT.error(`category.notfound`);
            return false;
        }
        if (price < 0) {
            sendT.error(`item.invalid.price`);
            return false;
        }

        let shopItem = shop.items[category].find((v) => item === v.item);
        if (!shopItem) {
            sendT.error(`item.notfound`);
            return false;
        }

        sendT.success(send.text(`item.setprice`).replace(/%item%/g, item).replace(/%price%/g, `${EconomyX.currency()}${price}`));
        shopItem.price=price;
        return true;
    }

    export function save(message: boolean = false): void {
        fs.writeFile(filePath, JSON.stringify(shop, null, 2), "utf8", (err) => {
            if (message) {
                if (err) {
                    send.error(`shop.json ${err}`);
                    throw err;
                }
                else send.success(`shop.json Saved!`);
            }
        });
    }
}

export namespace ShopForm {
    export function getItemButtons(items: ShopItem[]): FormButton[] {
        let buttons: FormButton[] = [];
        for (const [i, button] of items.entries()) {
            const item = ItemStack.constructWith(button.item, undefined, button.data);
            const _button = new FormButton(shop.shopui.buttons.item.replace("%name%", item.getCustomName()).replace("%price%", `${EconomyX.currency()}${button.price}`), button.path, button.icon);
            buttons.push(_button);
        }
        return buttons;
    }

    export function getCategoryButtons(categories: CompoundShop[]): FormButton[] {
        let buttons: FormButton[] = [];
        for (const [i, category] of categories.entries()) {
            const button = new FormButton(shop.shopui.buttons.category.replace("%name%", category.name), category.path, category.icon);
            buttons.push(button);
        }
        return buttons;
    }

    export function main(player: ServerPlayer): void {
        let categories: CompoundShop[] = [];

        ShopMain.getCategories().forEach((v) => {
            const category = ShopMain.getCompound(v);
            if (!category) return;
            categories.push(category);
        });
        const buttons = getCategoryButtons(categories);

        const form = new SimpleForm(shop.shopui.title, shop.shopui.description, buttons);
        form.sendTo(player.getNetworkIdentifier(), (f) => {
            const r = f.response;
            if (r === null) return;
            categoriesForm(ShopMain.getCategories()[r], categories[r], player);
        });
    }

    export function categoriesForm(category: string, compound: CompoundShop, player: ServerPlayer): void {
        let compounds: CompoundShop[] = [];
        let buttons: FormButton[] = [];
        const categories = Object.entries(compound.category);
        const items = ShopMain.getItems(category);
        if (!items) return;

        categories.forEach((v) => { compounds.push(v[1]) });
        const formCategories = getCategoryButtons(compounds);
        const formItems = getItemButtons(items);
        formCategories.forEach((v) => { buttons.push(v) });
        formItems.forEach((v) => { buttons.push(v) });

        const form = new SimpleForm(compound.name, compound.description, buttons);
        form.sendTo(player.getNetworkIdentifier(), (f) => {
            const r = f.response;
            if (r === null) return;
            if (r < formCategories.length) {
                categoriesForm(categories[r][0], categories[r][1], player);
                return;
            }
            if (r > (formCategories.length-1)) {
                const i = r-formCategories.length;
                buyForm(items[i], player);
                return;
            }
        });
    }

    export function buyForm(shopItem: ShopItem, player: ServerPlayer): void {
        const display = ItemStack.constructWith(shopItem.item, undefined, shopItem.data);
        const form = new CustomForm(display.getCustomName());
        let content: string = shop.shopui.buy_content.map((v) => v+"\n").toString().replace(/,/g, "§r").replace(/%player%/g, player.getName()).replace(/%money%/g, EconomyX.currency()+EconomyX.getMoney(player)).replace(/%item%/g, display.getCustomName()).replace(/%price%/g, EconomyX.currency()+shopItem.price);
        form.addComponent(new FormLabel(content));
        form.addComponent(new FormSlider(`Amount`, 1, 64));
        form.sendTo(player.getNetworkIdentifier(), (f) => {
            const r = f.response;
            if (r === null) return;
            ShopMain.buy(shopItem, r[1], player);
        });
    }
}
