import { Component } from "peura-ui";
import { cakeIngredients, cakeRecipe, iDontGetIt, items, psycErrorText, psychosisTexts, removeAllBut } from "./texts";
import AnswerUI from "./Answer";
import { EAction, type IItem, type IWord } from "./interfaces";
import PromptUI from "./Prompt";
import ItemRowUI from "./ItemRow";
import CookieUI from "./Cookies";
import MicrophonePopupUI from "./MicrophonePopup";
import AdvertisementUI from "./Advertisement";
import ReviewPopupUI from "./ReviewPopup";

const listPageTemplate = `
	<div class="ListPage_Root">
		<div class="ListPage_ChatWrapper">
			<div class="ListPage_ChatOutput" id="chat-output">
				{chat}
				<div class="ListPage_Thinking">{thinking}</div>
			</div>
			<div class="ListPage_InputWrapper">
				<input id="chat-input" class="Login_Input" value="{input}" onkeydown="{onKeyDownInput}"/>
				<button class="Login_Butt-Highlight" onclick="{onClickSend}">Lähetä</button>
			</div>
		</div>
		<div class="ListPage_Items">{items}</div>
		{cookies}
		{microphonePopup}
	</div>
`;

function capitalFirst(word: string) {
	return word[0]?.toLocaleUpperCase() + word.slice(1);
}

function getAddComplement(keyword: IWord): string {
	const answers = [
		`Todella hyvä idea! Lisään ${keyword.gen} ostoslistalle.`,
		`${capitalFirst(keyword.nom)} on mitä mainioin valinta. Laitan sen listaan.`,
		`Kerrassaan mahtava valinta! Lisään ${keyword.gen} kauppalistaan.`,
		`Loistovalinta! Lisään ${keyword.gen} ostoslistaan.`,
		`Lisään ${keyword.gen} listalle. Hyvä valinta.`,
		`Hienoa! ${capitalFirst(keyword.nom)} lisätty.`,
		`${capitalFirst(keyword.nom)} laitettu kauppalistaan. Oivallinen valinta!`,
		`Uskomaton valinta! Laitan ${keyword.gen} ostoslistalle.`,
		`Mahtava valinta! ${capitalFirst(keyword.nom)} laitettu kauppalistalle.`,
	];
	const index = Math.round(Math.random() * answers.length) % answers.length;
	return answers[index] || "";
}

function getRemovalAnswer(keyword: IWord) {
	const answers = [
		`Ymmärrän, otan ${keyword.gen} pois listalta.`,
		`Selvä homma! Salli minun poista ${keyword.nom} listasta.`,
		`On luonnollista että välillä tulee katumapäälle. Poistan ${keyword.gen} listalta.`,
		`Ei ongelmaa. Otan pois ${keyword.gen} kauppalistalta.`,
		`Ymmärretty! Poistan ${keyword.gen} pyytämäsi asiat.`,
		`Pyysin minua poistamaan ${keyword.gen}. Otan sen pois ostoslistalta.`,
		`Anna minun ottaa ${keyword.nom} pois ostoslistalta.`,
	];
	const index = Math.round(Math.random() * answers.length) % answers.length;
	return answers[index] || "";
}

function getRemovalAnswerPlural() {
	const answers = [
		`Ymmärrän, otan tavarat pois listalta.`,
		`Selvä homma, poistan asiat listasta.`,
		`On luonnollista että välillä tulee katumapäälle. Poistan ostokset listalta.`,
		`Ei ongelmaa. Otan pois tavarat kauppalistalta.`,
		`Ymmärretty! Poistan listasta pyytämäsi asiat.`,
		`Otan pyytämäsi asiat pois ostoslistalta.`,
	];
	const index = Math.round(Math.random() * answers.length) % answers.length;
	return answers[index] || "";
}

function isCake(input: string) {
	const trigs = [
		"kakku", "kakut", "kakun", "kakkujen", "kakkua", "kakkuja", "kakussa", "kakuissa", "kakusta",
		"kakuista", "kakkuun", "kakkuihin", "kakulla", "kakuilla", "kakulta", "kakuilta", "kakulle",
		"kakuille", "kakkuna", "kakkuina", "kakuksi", "kakuiksi", "kakuin", "kakutta", "kakuitta"
	];
	return trigs.some(trig => input.match(trig)) && !input.match("valmiskak") && !input.match("pakastekak");
}

export default class ListPageUI extends Component {

	private chatOutputElem: HTMLElement | null = null;
	private chatInputElem: HTMLElement | null = null;
	private reviewActivated = false;

	constructor(progress: () => void) {

		const chat: (PromptUI | AnswerUI)[] = [];
		const itemRows: ItemRowUI[] = [];
		let previusAct: EAction = EAction.None;
		let psychosis = false;
		let psycIndex = 0;
		let beforeCakeItems: string[] = [];
		let thinkingTime = 540;
		let adIntervalId = -1;

		const parseInput = (input: string) => {
			const addTrigs: (RegExp | string)[] = [
				/lisä(tä|(än|ät|ä|ämme|ätte|ävät)(kö|pä|ppä)*)/,
				/lisäisi(n|t)*(kö|tpä)*/,
				/lait(taa|(an|at|a|amme|atte|tavat)(ko|pa|ppa)*)/,
				/laittaisi(n|t)*(ko|tpa)/,
				/tarv(e|ita|ittais|its(i|e)|iin)/,
				"listaan", "listalle", "ostaa",
				/halu(an|ai|i)/, "haluta",
				/tekee ([a-zåäöA-ZÅÄÖ]+ )*miel/,
				/hank(ki|it|in)/
			];
			const removeTrigs: (RegExp | string)[] = [
				"pois",
				/poist(aa|(an|at|a|amme|atte|avat)(ko|pa|ppa)*)/,
				/poistaisi(n|t)*(ko|tpa)*/,
				"ostin", "ostettu", "hankin", "hankittu",
				"hoidettu", "hommattu", "lisätty",
				"listasta", "listalta"
			];
			const againTrigs: (RegExp | string)[] = [
				/^ja/, /^myös/, /^sekä/, /^myöskin/, /^niin ja/, /^ainiin ja/, /tarko(i)*t(a|i)n/
			];
			
			// Find items
			const matchingItemsRaw = items.filter(it => ` ${input} `.match(it.trig));
			const matchingItemsSet = new Set(matchingItemsRaw);
			const matchingItems = [...matchingItemsSet];

			// Choose action
			if (!psychosis) {
				if (input.match("eikun")) {
					psychosis = true;
					makeAnswer(psychosisTexts[0] || "", () => {
						handleAddBeforeCake();
					});
					psycIndex++;
					thinkingTime = 3500;
				}
				else if (againTrigs.some(trig => input.match(trig))) {
					if (previusAct === EAction.Add) {
						handleAdd(input, matchingItems);
					}
					else if (previusAct === EAction.Remove) {
						handleRemove(input, matchingItems);
					}
				}
				else if (removeTrigs.some(trig => input.match(trig))) {
					if (` ${input} `.match("edelliset")) {
						makeAnswer(removeAllBut, () => {
							removeAllItemsBut();
						});
					}
					else {
						handleRemove(input, matchingItems);
					}
				}
				else if (addTrigs.some(trig => input.match(trig))) {
					if (isCake(input)) {
						handleAdd(input, []);
					}
					else {
						if (matchingItems.length === 0) {
							const unknownItem = handleUnknownItem(input, addTrigs);
							if (unknownItem) {
								matchingItems.push(unknownItem);
							}
						}
						if (matchingItems.length > 0) {
							handleAdd(input, matchingItems);
						}
						else {
							console.error("Don't understand 2");
							makeAnswer(iDontGetIt, () => {});
						}
					}
				}
				else {
					console.error("Don't understand 1");
					makeAnswer(iDontGetIt, () => {});
				}
			}
			else {
				if (psycIndex === 1) {
					makeAnswer(psychosisTexts[psycIndex] || "", () => {
						itemRows.push(new ItemRowUI("🦀"));
						this.hooks.items = itemRows;
					});
					psycIndex++;
				}
				else if (psycIndex >= 2) {
					console.log("asd");
					if (psycIndex >= 3) {
						if (adIntervalId >= 0) {
							window.clearInterval(adIntervalId);
							adIntervalId = -1;
						}
					}
					if (psycIndex >= 6) {
						window.setTimeout(() => {
							progress();
						}, 500);
					}
					makeAnswer(psychosisTexts[psycIndex] || "", () => {
						if (psycIndex > 4) {
							this.hooks.items = [new ItemRowUI(psycErrorText)];
						}
					});
					psycIndex++;
				}
			}
		}

		const handleAddBeforeCake = () => {
			let itemIndex = 0;
			const addItem = () => {
				itemRows.splice(0, 0, new ItemRowUI(beforeCakeItems[itemIndex] || ""));
				this.hooks.items = itemRows;
				itemIndex++;
				if (itemIndex < beforeCakeItems.length) {
					window.setTimeout(() => {
						addItem();
					}, 450);
				}
				else {
					itemRows.splice(-1, 1);
					this.hooks.items = itemRows;
				}
			}
			addItem();
		}

		const removeAllItemsBut = () => {
			const removeItem = () => {
				itemRows.splice(0, 1);
				this.hooks.items = itemRows;
				if (itemRows.length > 1) {
					window.setTimeout(() => {
						removeItem();
					}, 130);
				}
			}
			removeItem();
		}


		const handleUnknownItem = (input: string, trigs: (RegExp | string)[]) => {
			const inputArr = input.split(" ");
			let actionIndex = -1;
			let result: IItem | null = null;
			for (let i = 0; i < inputArr.length; i++) {
				if (actionIndex > -1 && !inputArr[i]?.match(/list/)) {
					result = {
						trig: /jotain/,
						out: { nom: inputArr[i] || "", gen: inputArr[i] + "n" || "" },
						story: ""
					};
				}
				if (trigs.some(trig => inputArr[i]?.match(trig))) {
					actionIndex = i;
				}
			}
			return result;
		}

		const handleAdd = (input: string, items: IItem[]) => {
			previusAct = EAction.Add;
			if (isCake(input)) {
				beforeCakeItems = itemRows.map(itemRow => itemRow.item);
				makeAnswer(cakeRecipe, () => {});
				addToList(cakeIngredients);
			}
			else if (items?.length) {
				let itemIndex = 0;
				const addItem = () => {
					const item = items[itemIndex];
					itemIndex++;
					if (item) {
						const randomSucc = Math.random() > 0.05;
						const answer = randomSucc
							? item.story + "\n" + getAddComplement(item.out)
							: getAddComplement(item.out);
						makeAnswer(answer, () => {
							if (randomSucc) {
								if (item.out.nom === "leipä") {
									addToList(item);
									addToList(item);
								}
								else {
									addToList(item);
								}
							}
							addItem();
						});
					}
				}
				addItem();
			}
		}

		const handleRemove = (input: string, items: IItem[]) => {
			previusAct = EAction.Remove;
			const answer = items.length > 1
				? getRemovalAnswerPlural()
				: getRemovalAnswer(items[0]?.out || { nom: "", gen: ""});

			let itemIndex = 0;
			const removeItem = () => {
				const item = items[itemIndex];
				itemIndex++;
				if (item) {
					window.setTimeout(() => {
						const removalItem = itemRows.find(itemRow => itemRow.item === item.out.nom);
						if (removalItem) {
							const removeIndex = itemRows.indexOf(removalItem);
							itemRows.splice(removeIndex, 1);
							this.hooks.items = itemRows;
						}
						removeItem();
					}, 170);
				}
			}
			makeAnswer(answer, () => {
				removeItem();
			});
		}

		const makeAnswer = (answer: string, answerReady: () => void) => {
			chat.push(new AnswerUI(answer, () => {
				if (this.chatOutputElem) {
					this.chatOutputElem.scrollTo(0, this.chatOutputElem.scrollHeight);
				}
			}, answerReady));
			this.hooks.chat = chat;
		};

		const addToList = (item: IItem | string[]) => {
			if (Array.isArray(item)) {
				let idx = 0;
				const addItems = () => {
					if (idx < item.length) {
						itemRows.push(new ItemRowUI(item[idx] || ""));
						this.hooks.items = itemRows;
						idx++;
						window.setTimeout(addItems, 180);
					}
				}
				window.setTimeout(addItems, 1200);
			}
			else {
				itemRows.push(new ItemRowUI(item));
				this.hooks.items = itemRows;
			}
		};

		const sendInput = () => {
			const input = this.hooks.input;
			this.hooks.input = "";
			chat.push(new PromptUI(input));
			this.hooks.chat = chat;

			// Thinking
			let thinkDotQty = 0;
			const intervalId = window.setInterval(() => {
				this.hooks.thinking = "Mietin" + ".".repeat(thinkDotQty);
				if (this.chatOutputElem) {
					this.chatOutputElem.scrollTo(0, this.chatOutputElem.scrollHeight)
				}
				thinkDotQty += 1;
				if (thinkDotQty > 3) thinkDotQty = 0;
			}, 110);

			if (psycIndex > 4) {
				parseInput(input);
			}
			else {
				window.setTimeout(() => {
					this.hooks.thinking = "";
					window.clearInterval(intervalId);
					parseInput(input);
				}, thinkingTime);
			}
		}

		super(listPageTemplate, {
			onKeyDownInput: (event: KeyboardEvent) => {
				if (event.key === "Enter") {
					sendInput();
				}
			},
			onClickSend: sendInput
		});

		let adId = 0;
		window.setTimeout(() => {
			this.hooks.cookies = new CookieUI(() => {
				this.hooks.cookies = null;
				window.setTimeout(() => {
					adIntervalId = window.setInterval(() => {
						chat.push(new AdvertisementUI(adId));
						adId++;
						this.hooks.chat = chat;
						if (this.chatOutputElem) {
							this.chatOutputElem.scrollTo(0, this.chatOutputElem.scrollHeight)
						}
					}, 35000);
					chat.push(new AdvertisementUI(adId));
					adId++;
					this.hooks.chat = chat;
				}, 3000);
			}, false);
		}, 1100);

		window.setTimeout(() => {
			this.hooks.microphonePopup = new MicrophonePopupUI(() => {
				this.hooks.microphonePopup = null;
			});
		}, 4300);
	}

	afterMount(): void {
		window.setTimeout(() => {
			const handleReview = () => {
				if (!this.reviewActivated) {
					window.setTimeout(() => {
						this.hooks.microphonePopup = new ReviewPopupUI(() => {
							this.hooks.microphonePopup = null;
							this.chatInputElem?.removeEventListener("mouseenter", handleReview);
						})
					}, 400);
				}
				this.reviewActivated = true;
			};
			this.chatOutputElem = document.getElementById("chat-output");
			this.chatInputElem = document.getElementById("chat-input");
			this.chatInputElem?.addEventListener("mouseenter", handleReview)
		}, 400);
	}
}
