import {libWrapper, UtilLibWrapper} from "./PatcherLibWrapper.js";
import {SharedConsts} from "../shared/SharedConsts.js";
import {Config} from "./Config.js";
import {LGT} from "./Util.js";

class Patcher_Token {
	static init () {
		libWrapper.register(
			SharedConsts.MODULE_NAME,
			"Token.prototype.refresh",
			function (fn, ...args) {
				if (Config.get("tokens", "isDisplayDamageDealt")) Patcher_Token._handleConfigUpdate_displayDamageDealt_doUpdateDisplay(this);
				return fn(...args);
			},
			UtilLibWrapper.LIBWRAPPER_MODE_WRAPPER,
		);

		libWrapper.register(
			SharedConsts.MODULE_NAME,
			"Token.prototype._onUpdate",
			function (fn, ...args) {
				if (Config.get("tokens", "isDisplayDamageDealt")) Patcher_Token._handleConfigUpdate_displayDamageDealt_doUpdateDisplay(this);
				return fn(...args);
			},
			UtilLibWrapper.LIBWRAPPER_MODE_WRAPPER,
		);

		libWrapper.register(
			SharedConsts.MODULE_NAME,
			"TokenDocument.prototype._onUpdateTokenActor",
			function (fn, ...args) {
				if (Config.get("tokens", "isDisplayDamageDealt")) Patcher_Token._handleConfigUpdate_displayDamageDealt_doUpdateDisplay(this.object);
				return fn(...args);
			},
			UtilLibWrapper.LIBWRAPPER_MODE_WRAPPER,
		);

		libWrapper.register(
			SharedConsts.MODULE_NAME,
			"TokenDocument.prototype._onUpdateBaseActor",
			function (fn, ...args) {
				if (Config.get("tokens", "isDisplayDamageDealt")) Patcher_Token._handleConfigUpdate_displayDamageDealt_doUpdateDisplay(this.object);
				return fn(...args);
			},
			UtilLibWrapper.LIBWRAPPER_MODE_WRAPPER,
		);
	}

	static handleConfigUpdate () {
		this._handleConfigUpdate_displayDamageDealt_doRefreshTokens();
	}

	/**
	 * @param [opts]
	 * @param [opts.isRemoveDisplays] If the custom displays should be removed.
	 */
	static _handleConfigUpdate_displayDamageDealt_doRefreshTokens (opts) {
		opts = opts || {};

		const tokens = MiscUtil.get(canvas, "tokens", "placeables") || [];
		for (const token of tokens) {
			try {
				if (opts.isRemoveDisplays && token._plutonium_xDispDamageDealt) {
					token.removeChild(token._plutonium_xDispDamageDealt);
					token._plutonium_xDispDamageDealt = null;
				}
				token.refresh();
			} catch (e) {
				// Sanity check/should never occur
				console.warn(...LGT, `Failed to refresh token "${token.id}"!`, e);
			}
		}
	}

	static _handleConfigUpdate_displayDamageDealt_doUpdateDisplay (token) {
		this._handleConfigUpdate_displayDamageDealt_doAddDisplay(token);

		const maxHp = MiscUtil.get(token.actor, "data", "data", "attributes", "hp", "max") || 0;
		const curHp = MiscUtil.get(token.actor, "data", "data", "attributes", "hp", "value") || 0;

		const damageDealt = Math.min(maxHp, Math.max(0, maxHp - curHp));
		token._plutonium_xDispDamageDealt.text = `-${damageDealt}`;

		token._plutonium_xDispDamageDealt.visible = !!damageDealt;

		if (curHp <= Math.floor(maxHp / 2)) token._plutonium_xDispDamageDealt.style.fill = 0xFF0000;
		else token._plutonium_xDispDamageDealt.style.fill = 0xFFFFFF;
	}

	static _handleConfigUpdate_displayDamageDealt_doAddDisplay (token) {
		if (
			token._plutonium_xDispDamageDealt
			&& token._plutonium_xDispDamageDealt.parent // Our display can become orphaned--in this case, we need to regenerate it
		) return;

		// If orphaned, cleanup to prevent any leaks
		if (token._plutonium_xDispDamageDealt && !token._plutonium_xDispDamageDealt.parent) {
			token.removeChild(token._plutonium_xDispDamageDealt);
			token._plutonium_xDispDamageDealt = null;
		}

		// region Based on "Token._drawNameplate()"
		// Create the nameplate text
		token._plutonium_xDispDamageDealt = new PIXI.Text("", CONFIG.canvasTextStyle.clone());
		token._plutonium_xDispDamageDealt.style.fontSize = 24;

		// Anchor text to the bottom-right of the nameplate
		token._plutonium_xDispDamageDealt.anchor.set(1, 1);

		// Set position at bottom-right of token (with small offsets)
		token._plutonium_xDispDamageDealt.position.set(token.w - 3, token.h - 1);

		token.addChild(token._plutonium_xDispDamageDealt)
	}
}

export {Patcher_Token};
