import { FilterType, RecipeCompendium } from "./RecipeCompendium.js";
import { Crafting, getCurrencyComponent } from "../Crafting.js";
import { getDataFrom, sanitizeUuid } from "../helpers/Utility.js";
import { Settings } from "../Settings.js";
import { AnyOf } from "../AnyOf.js";
import { Recipe } from "../Recipe.js";
import { TestHandler } from "../TestHandler.js";
import { sortByFolder } from "../helpers/Folder.js";
export class CraftingApp extends Application {
	constructor(actor, options = {}) {
		super(options);
		this.data = {
			actor: actor,
			filter: FilterType.available,
			search: "",
			recipes: [],
			filterItems: {},
			folders: {},
		};
		if (this.element.length > 0) {
			this.bringToTop();
		}
	}
	async close(options) {
		Settings.set(Settings.CRAFTING_APP_WIDTH, this.position.width);
		Settings.set(Settings.CRAFTING_APP_HEIGHT, this.position.height);
		return super.close(options);
	}
	static get defaultOptions() {
		return foundry.utils.mergeObject(super.defaultOptions, {
			// @ts-ignore
			title: game.i18n.localize(`beaversCrafting.crafting-app.title`),
			width: Settings.get(Settings.CRAFTING_APP_WIDTH),
			height: Settings.get(Settings.CRAFTING_APP_HEIGHT),
			template: "modules/beavers-crafting/templates/crafting-app.hbs",
			closeOnSubmit: true,
			submitOnClose: true,
			submitOnChange: true,
			resizable: true,
			classes: ["sheet", "beavers-crafting", "crafting-app"],
			popOut: true,
			id: 'beavers-crafting'
		});
	}
	async getData(options = {}) {
		const data = foundry.utils.mergeObject(this.data, await super.getData(options));
		let recipes = await RecipeCompendium.filterForActor(data.actor, data.filter);
		if (Object.values(data.filterItems).length != 0) {
			recipes = await RecipeCompendium.filterForItems(recipes, Object.values(data.filterItems));
		}
		if (data.search) {
			const search = data.search.toLowerCase();
			recipes = recipes.filter(r => r.name.toLowerCase().includes(search));
		}
		data.folders = sortByFolder(recipes);
		data.recipes = recipes;
		if (!data.selected) {
			data.selected = data.recipes[0]?.uuid;
		}
		this.selectRecipe(data.selected);
		data.content = null;
		return data;
	}
	selectRecipe(uuid) {
		this.data.selected = uuid;
		this.data.recipes.forEach(r => {
			if (r.uuid === uuid) {
				this.data.recipe = Recipe.clone(r);
				return;
			}
		});
	}
	async renderRecipeSheet() {
		if (this.data.recipe === undefined || this.element === null) {
			return;
		}
		const crafting = await Crafting.fromRecipe(this.data.actor.id, this.data.recipe);
		await crafting.checkCurrency();
		RecipeCompendium.validateRecipeToItemList(RecipeCompendium._filterData(this.data.recipe.input, (c) => c.type === "Item"), this.data.actor.items, crafting.result);
		await crafting.checkRequired();
		this.data.result = crafting.result;
		this.data.content = await renderTemplate('modules/beavers-crafting/templates/crafting-app-main.hbs', {
			recipe: this.data.recipe,
			currencyComponent: this.data.recipe.currency ? getCurrencyComponent(this.data.recipe.currency.name, this.data.recipe.currency.value) : undefined,
			precast: await this.getPrecastFromResult(this.data.result, this.data.recipe),
			maxHits: this.data.recipe.beaversTests ? TestHandler.getMaxHits(this.data.recipe.beaversTests) : 0,
			displayResults: Settings.get(Settings.DISPLAY_RESULTS),
			displayIngredients: Settings.get(Settings.DISPLAY_RESULTS),
			useAttendants: Settings.get(Settings.USE_ATTENDANTS),
			hasCraftedFlag: Settings.get(Settings.SEPARATE_CRAFTED_ITEMS) !== "none",
		});
		this.element.find(".sheet-body").empty();
		this.element.find(".sheet-body").append(this.data.content);
		this.activateRecipeSheetListener(this.element);
	}
	activateListeners(html) {
		super.activateListeners(html);
		html.find(".sidebar select.filter").on("change", (e) => {
			this.data.filter = $(e.target).val();
			this.data.selected = null;
			this.data.content = null;
			this.data.folders = {};
			this.render();
		});
		html.find(".sidebar input.search").on("input", (e) => {
			this.data.search = $(e.target).val();
			this.data.selected = null;
			this.data.content = null;
			this.data.folders = {};
			this.render();
		});
		if (this.data.search) {
			const searchInput = html.find(".sidebar input.search");
			searchInput.focus();
			const val = searchInput.val();
			searchInput.val("");
			searchInput.val(val);
		}
		html.find(".sidebar .navigation .beavers-folder-item").on("click", (e) => {
			const id = $(e.currentTarget).data().id;
			this.selectRecipe(id);
			html.find(".sidebar .navigation .selected").removeClass("selected");
			html.find(".sidebar .navigation .beavers-folder-item[data-id='" + id + "']").addClass("selected");
			void this.renderRecipeSheet();
		});
		html.find(".folderName").on("click", (e) => {
			$(e.currentTarget).parent(".folder").toggleClass(["open", "close"]);
		});
		html.find(".sidebar .fa-sort-amount-up").on("click", (e) => {
			html.find(".navigation .folder").removeClass("open").addClass("close");
		});
		void this.renderRecipeSheet();
	}
	activateRecipeSheetListener(html) {
		html.find('.results .clickable').on("click", e => {
			const uuid = $(e.currentTarget).data("id");
			if (Settings.get(Settings.DISPLAY_RESULTS)) {
				beaversSystemInterface.uuidToDocument(uuid).then(i => i.sheet.render(true));
			}
		});
		html.find('.ingredients .clickable').on("click", e => {
			const uuid = $(e.currentTarget).data("id");
			if (Settings.get(Settings.DISPLAY_INGREDIENTS)) {
				beaversSystemInterface.uuidToDocument(uuid).then(i => i.sheet.render(true));
			}
		});
		html.find('.attendants .clickable').on("click", e => {
			const uuid = $(e.currentTarget).data("id");
			if (Settings.get(Settings.DISPLAY_INGREDIENTS)) {
				beaversSystemInterface.uuidToDocument(uuid).then(i => i.sheet.render(true));
			}
		});
		html.find(".main .folderName").on("click", (e) => {
			$(e.currentTarget).parent(".folder").toggleClass(["open", "close"]);
		});
		html.find(".dialog-button").on("click", (e) => {
			if (this.data.recipe === undefined) {
				return;
			}
			Crafting.fromRecipe(this.data.actor.id, this.data.recipe)
				.then(crafting => {
				return crafting.craft();
			}).then(result => {
				this.close();
			});
		});
		html.find(".choose").on("click", e => {
			const group = $(e.currentTarget).data("group");
			const key = $(e.currentTarget).data("key");
			const type = $(e.currentTarget).data("type");
			this._choose(type, group, key);
			window.setTimeout(this.renderRecipeSheet.bind(this), 100);
		});
		html.find(".chooseAnyOf").on("click", e => {
			const group = $(e.currentTarget).data("group");
			const key = $(e.currentTarget).data("key");
			const type = $(e.currentTarget).data("type");
			if (this.data.recipe != undefined) {
				const pool = type === "output" ? game["items"].contents : this.data.actor.items;
				RecipeCompendium.evaluateAnyOf(type, this.data.recipe, group, key, pool)
					.then(() => window.setTimeout(this.renderRecipeSheet.bind(this), 100));
			}
		});
		this.addDragDrop(html);
	}
	_choose(type, group, key) {
		if (this.data.recipe) {
			const component = this.data.recipe[type][group][key];
			this.data.recipe[type][group] = {};
			this.data.recipe._addData(type, component, key, group);
		}
	}
	addDragDrop(html) {
		const dropFilter = new DragDrop({
			dropSelector: '.drop-area, .ingredients .flexrow',
			permissions: {
				dragstart: this._canDragStart.bind(this),
				drop: this._canDragDrop.bind(this)
			},
			callbacks: {
				dragstart: this._onDragStart.bind(this),
				dragover: this._onDragOver.bind(this),
				drop: this._onDrop.bind(this)
			}
		});
		for (const x in this._dragDrop) {
			if (this._dragDrop[x].dropSelector === dropFilter.dropSelector) {
				this._dragDrop[x].bind(html[0]);
				return;
			}
		}
		this._dragDrop.push(dropFilter);
		dropFilter.bind(html[0]);
	}
	async _onDrop(e) {
		const isFilterDrop = $(e.target).hasClass("drop-area");
		if (isFilterDrop) {
			return this._onDropFilter(e);
		}
		const uuid = $(e.currentTarget).data("id");
		if (uuid != undefined) {
			const key = $(e.currentTarget).data("key");
			const group = $(e.currentTarget).data("group");
			beaversSystemInterface.uuidToDocument(uuid).then(item => {
				if (AnyOf.isAnyOf(item)) {
					return this._onDropAnyOf(new AnyOf(item), group, key, e);
				}
				return;
			});
		}
	}
	async _onDropAnyOf(anyOf, group, key, e) {
		if (this.data.recipe === undefined || e["isHandled"]) {
			return;
		}
		const data = getDataFrom(e);
		if (data) {
			if (data.type !== "Item")
				return;
			const entity = await fromUuid(data.uuid);
			let result = await anyOf.executeMacro(entity);
			if (result.value) {
				const previousComponent = this.data.recipe.input[group][key];
				const component = beaversSystemInterface.componentFromEntity(entity);
				const id = sanitizeUuid(data.uuid);
				component.quantity = previousComponent.quantity;
				this.data.recipe = Recipe.clone(this.data.recipe);
				//remove existing ingredient with same id and add quantity;
				if (this.data.recipe.input[group][id]) {
					component.quantity = component.quantity + this.data.recipe.input[group][id].quantity;
					delete this.data.recipe.input[group][id];
				}
				//copyInPlace;
				const ingredients = Object.fromEntries(Object.entries(this.data.recipe.input[group]).map(([o_key, o_val]) => {
					if (o_key === key)
						return [id, component];
					return [o_key, o_val];
				}));
				this.data.recipe.input[group] = ingredients;
				e["isHandled"] = true;
				window.setTimeout(this.renderRecipeSheet.bind(this), 100);
			}
		}
	}
	async _onDropFilter(e) {
		const data = getDataFrom(e);
		if (data) {
			if (data.type !== "Item")
				return;
			let entity = await fromUuid(data.uuid);
			this.data.filterItems[data.uuid] = entity;
			this.render();
		}
	}
	async getPrecastFromResult(result, recipe) {
		const preCastData = {
			required: {},
			input: {},
		};
		if (result._currencyResult) {
			preCastData.currencies = { status: result._currencyResult.hasError ? 'error' : 'success' };
		}
		for (const group in recipe.input) {
			preCastData.input[group] = {};
			for (const key in recipe.input[group]) {
				const component = recipe.input[group][key];
				if (result._components.consumed.findComponentResult(component)) {
					preCastData.input[group][key] = result._components.consumed.hasError(component) ? 'error' : 'success';
				}
				else {
					preCastData.input[group][key] = 'unknown';
				}
			}
		}
		for (const group in recipe.required) {
			preCastData.required[group] = {};
			for (const key in recipe.required[group]) {
				const component = recipe.required[group][key];
				if (result._components.required.findComponentResult(component)) {
					preCastData.required[group][key] = result._components.required.hasError(component) ? 'error' : 'success';
				}
				else {
					preCastData.required[group][key] = 'unknown';
				}
			}
		}
		return preCastData;
	}
	_canDragDrop(selector) {
		return true;
	}
}
