import { createGetLootRecord } from "db/dbGetLoot";
import { getUserRecord, updateUserRecord } from "db/dbUser";
import itemMap, { type inventory, type items } from "items";
import { Command, sendMessage } from "lib/commandUtils";
import { buildTimeString } from "lib/dateManager";
import { isInvuln, removeInvuln } from "lib/invuln";
import { redis } from "lib/redis";
import { timeout } from "lib/timeout";
import { streamerUsers } from "main";
import { playAlert } from "web/alerts/serverFunctions";

const COOLDOWN = 10 * 60; // 10 mins (s)

export default new Command({
	name: "getloot",
	aliases: ["getloot", "dig", "loot", "mine"],
	usertype: "chatter",
	execution: async (msg, user) => {
		if (!(await redis.exists("streamIsLive"))) {
			await sendMessage(`No loot while stream is offline`, msg.messageId);
			return;
		}
		if (
			(await isInvuln(msg.chatterId)) &&
			!streamerUsers.includes(msg.chatterId)
		) {
			await sendMessage(
				`You're no longer an invuln because used a lootbox.`,
				msg.messageId,
			);
			await removeInvuln(msg.chatterId);
		}
		if (await user.itemLock()) {
			await sendMessage(`Cannot get loot (itemlock)`, msg.messageId);
			return;
		}
		await user.setLock();
		const userData = await getUserRecord(user);
		const timeData =
			(await redis.expiretime(`user:${user.id}:lootboxcooldown`)) * 1000;
		if (timeData > Date.now()) {
			await user.clearLock();
			if (await user.greedy()) {
				await Promise.all([
					sendMessage(
						`${user.displayName} STOP BEING GREEDY!!! UltraMad UltraMad UltraMad`,
					),
					timeout(
						user,
						`Wait ${buildTimeString(timeData, Date.now())} for another lootbox`,
						60,
					),
				]);
				return;
			} else {
				await Promise.all([
					user.setGreed(),
					sendMessage(
						`Wait ${buildTimeString(timeData, Date.now())} for another lootbox.`,
						msg.messageId,
					),
				]);
				return;
			}
		}

		await user.clearGreed();

		await redis.set(`user:${user.id}:lootboxcooldown`, "1");
		await redis.expire(`user:${user.id}:lootboxcooldown`, COOLDOWN);

		if (
			!(await redis.exists(`user:${user.id}:subbed`)) &&
			Math.random() < 0.1
		) {
			await Promise.all([
				user.clearLock(),
				updateUserRecord(user, userData),
				timeout(user, "THE LOOTBOX WAS TRAPPED!!!", 60),
				sendMessage(
					`wybuh wybuh ${user.displayName.toUpperCase()} FOUND A TRAPPED LOOTBOX!!! wybuh wybuh`,
				),
				playAlert({
					name: "grenadeExplosion",
					user: "trapped lootbox",
					target: user.displayName,
				}),
			]);
			return;
		}
		const gainedqbucks = Math.floor(Math.random() * 100) + 50; // range from 50 to 150
		userData.balance += gainedqbucks;

		const itemDiff: inventory = {
			grenade: 0,
			blaster: 0,
			tnt: 0,
			silverbullet: 0,
		};

		for (let i = 0; i < 3; i++) {
			if (Math.floor(Math.random() * 5) === 0) itemDiff.grenade! += 1; // 1 in 5
			if (Math.floor(Math.random() * 5) === 0) itemDiff.blaster! += 1; // 1 in 5
			if (Math.floor(Math.random() * 50) === 0) itemDiff.tnt! += 1; // 1 in 50
			if (Math.floor(Math.random() * 50) === 0) itemDiff.silverbullet! += 1; // 1 in 50
		}

		for (const [item, amount] of Object.entries(itemDiff) as [
			items,
			number,
		][]) {
			if (userData.inventory[item]) userData.inventory[item] += amount;
			else userData.inventory[item] = amount;
		}

		const itemstrings: string[] = [`${gainedqbucks} qbucks`];

		for (const [item, amount] of Object.entries(itemDiff)) {
			if (amount === 0) continue;
			const selection = itemMap.get(item);
			if (!selection) continue;
			itemstrings.push(
				`${amount} ${selection.prettyName + (amount === 1 ? "" : selection.plural)}`,
			);
		}

		const last = itemstrings.pop();
		const itemstring =
			itemstrings.length === 0 ? last : `${itemstrings.join(", ")} and ${last}`;
		const message = `You got ${itemstring}`;

		await Promise.all([
			updateUserRecord(user, userData),
			sendMessage(message, msg.messageId),
			createGetLootRecord(user, gainedqbucks, itemDiff, "getloot"),
			user.clearLock(),
		]);

		if (itemstrings.length === 0 && gainedqbucks < 100)
			await sendMessage("YEOP THAT'S A SCAMBOX YEOP");
	},
});
