'use strict';

const conf = require('../conf');
const {sleep, nextTick} = require('../utils');

class Craft{
	constructor(args){
		this.bot = args.bot;
		this.interval = args.interval;
		this.target = args.target;
		this.intervalStop;
		this.isAction = true;
	}

	init(){
		return new Promise(async (resolve, reject)=>{
			this.bot.on('onReady', async ()=>{
				try{
					await sleep(500);
					await this.bot.goTo({
						where: this.bot.findBlockBySign('bot walk 2').position,
						range: 0,
					});

					await this.bot.goTo({
						where: this.bot.findBlockBySign('bot walk 1').position,
						range: 0,
					});

					await this.bot.goTo({
						where: this.bot.findBlockBySign('bot walk 2').position,
						range: 0,
					});

					let hasItems = await this.getItems();

					while(hasItems){
						await this.craft();
						hasItems = await this.getItems();
					}

					return resolve();

				}catch(error){
					reject(error);
				}

			});			
		});
	}

	unload(){
		if(this.intervalStop){
			clearInterval(this.intervalStop);
			this.intervalStop = undefined;
		}
		return true;
	}

	async getItems(){
		/* 
		shards 
		*/
		let prismarine_shardChest = this.bot.findChestBySign('prismarine_shard');
		await this.bot.goTo({
			where: prismarine_shardChest.position,
			range: 2,
		});

		let hasShard = await this.bot.checkItemsFromContainer(
			prismarine_shardChest, 'prismarine_shard', 64*4
		);

		/*
		crystals
		*/
		let prismarine_crystalsChest = this.bot.findChestBySign('crystals');
		await this.bot.goTo({
			where: prismarine_crystalsChest.position,
			range: 2,
		});

		let hasCrystals = await this.bot.checkItemsFromContainer(
			prismarine_crystalsChest, 'prismarine_crystals', 64*5
		);

		if(!hasShard || !hasCrystals) return false;

		/*
		get
		*/
		await sleep(3000);

		await this.bot.getItemsFromChest(
			prismarine_shardChest, 'prismarine_shard', 64*4
		);
		await sleep(1000);

		await this.bot.getItemsFromChest(
			prismarine_crystalsChest, 'prismarine_crystals', 64*5
		);

		return true;
	}

	async craft(){

		// Ensure the bot has enough items (4 shards and 5 crystals for 1 lantern)
		let prismarineShardsCount = this.bot.bot.inventory.count(this.bot.mcData.itemsByName.prismarine_shard.id);
		let prismarineCrystalsCount = this.bot.bot.inventory.count(this.bot.mcData.itemsByName.prismarine_crystals.id);

		if(prismarineShardsCount < 4 || prismarineCrystalsCount < 5){
		  console.log("Not enough materials to craft 64 Sea Lanterns.");
		  return;
		}else{
			console.log('good to make sea_lantern!')
		}

		// Hold onto the closest crafting table
		let craftingTable = this.bot.bot.findBlock({
			matching: this.bot.mcData.blocksByName.crafting_table.id,
			maxDistance: 64
		});

		await this.bot.goTo({
			where: craftingTable.position,
			range: 1,
		});

		// Hold onto the recipe
		let recipe = this.bot.bot.recipesAll(
			this.bot.mcData.itemsByName.sea_lantern.id,
			null,
			craftingTable
		)[0];

		let window = await this.bot.openCraftingTable(craftingTable);

		// Move these into openCrating function
		let windowOnce = (event)=> new Promise((resolve, reject)=> window.once(event, resolve));
		let inventory = window.slots.slice(window.inventoryStart, window.inventoryEnd);

		// Move the items into the crafting grid
		// Keep track of used inventory slots to avoid reusing the same slot
		let usedInventorySlots = new Set();
		let slotCount = 1;
		for(let shapeRow of recipe.inShape){
			for(let shape of shapeRow){
				let inventorySlot = inventory.findIndex((element, index) =>
					element && element.type === shape.id && !usedInventorySlots.has(index)
				);
				if (inventorySlot === -1) {
					throw new Error(`Not enough items of type ${shape.id} in inventory`);
				}
				let actualSlot = window.inventoryStart + inventorySlot;
				usedInventorySlots.add(inventorySlot);

				this.bot.bot.moveSlotItem(actualSlot, slotCount);
				await windowOnce(`updateSlot:${slotCount}`);
				slotCount++;
			}
		}

		// Wait for the server to catch up.
		await sleep(500);

		// Craft each item until all are gone.
		let craftedCount = 0;
		while(window.slots[0]){
			await this.bot.bot.moveSlotItem(
				window.craftingResultSlot,
				38 // dont hard code this!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
			);
			craftedCount++;
			await windowOnce(`updateSlot:0`);
			await sleep(50); // wait for the client to catchup
		}

		await window.close();

		/*
		Dump items to chest
		*/

		let seaLanternChest = this.bot.findChestBySign('sea_lantern');
		await this.bot.goTo({
			where: seaLanternChest.position,
			range: 4,
		});

		await this.bot.dumpToChest(seaLanternChest, 'sea_lantern')
	}
}

Craft.getStatus = function(instance) {
	return { active: true, target: 'sea_lantern' };
};

module.exports = Craft;
