// TODO: make this less hacky in the future.
// TODO: add popup that appears if the user forgot to decompile the game before using the modmanager.

/**
 * @namespace MATTIE.compat
 * @description the name space used for compatibility changes
 * */
MATTIE.compat = MATTIE.compat || {};

/** @description whether decryption of images should be forcibly stopped or not */
MATTIE.compat.pauseDecrypt = false;

/**
 * @description weather or not files should be decrypted and saved to their unencrypted sate while playing the game
 * this has some benefits and some drawbacks. This should not be any better than leaving the files encrypted as it decrypts them first anyways
 * this might be useful for some edge cases though.
 * @default false
 */
MATTIE.compat.runtime_decrypt = false;

/**
 * @description set the field hasEncryptedImages to true or false in memory and system.json
 * @param {boolean} bool
 */
MATTIE.compat.setEncryptedImagesInSystemJson = function (bool) {
	const fs = require('fs');
	sysJsonPath = `${MATTIE.DataManager.localGamePath()}/data/System.json`;
	Decrypter.hasEncryptedImages = bool;
	console.log('system.json loading');
	if (fs.existsSync(sysJsonPath)) {
		console.log('system.json found');
		contents = JSON.parse(fs.readFileSync(sysJsonPath));
		contents.hasEncryptedImages = bool;
		contents = JSON.stringify(contents);
		fs.writeFileSync(sysJsonPath, contents);
	}
	console.log('system.json updated');
};

Bitmap.prototype.decryptAndSave = function (url) {
	let pngUrl = `${MATTIE.DataManager.localGamePath()}/`;
	let rpgMVPUrl = `${pngUrl}/`;
	if (url.endsWith('.rpgmvp')) {
		rpgMVPUrl += url;
		pngUrl += url.replace('.rpgmvp', '.png');
	} else if (url.endsWith('.png')) {
		rpgMVPUrl += url.replace('.png', '.rpgmvp');
		pngUrl += url;
	}

	pngUrl = decodeURIComponent(pngUrl);
	rpgMVPUrl = decodeURIComponent(rpgMVPUrl);

	this._loadingState = 'decrypting';
	Decrypter.decryptImg(pngUrl, this);
	// MATTIE.imageAPI.saveBitmapToFile(this,pngUrl)
	console.log('image decrypted');
};

/**
 * @description a loader for assets that can load encrypted and unencrypted files
 * slightly heavier as it is using fs.existssync
 */
Bitmap.prototype.compatabilityLoad = function (url, force = false) {
	var fs = require('fs');

	try {
		let pngUrl = `${MATTIE.DataManager.localGamePath()}/`;
		let rpgMVPUrl = `${pngUrl}/`;

		if (url.endsWith('.rpgmvp')) {
			rpgMVPUrl += url;
			pngUrl += url.replace('.rpgmvp', '.png');
		} else if (url.endsWith('.png')) {
			rpgMVPUrl += url.replace('.png', '.rpgmvp');
			pngUrl += url;
		}

		// pngUrl = decodeURIComponent(pngUrl);
		// rpgMVPUrl = decodeURIComponent(rpgMVPUrl);

		console.log(rpgMVPUrl);

		rpgmakerWantsToDecrypt = !Decrypter.checkImgIgnore(url) && Decrypter.hasEncryptedImages;
		modmanagerWantsToDecrypt = fs.existsSync(rpgMVPUrl) && !MATTIE.compat.pauseDecrypt;
		cannotUseEncrypted = !fs.existsSync(rpgMVPUrl) && fs.existsSync(pngUrl);

		console.log(`modmanger want to decrypt:${modmanagerWantsToDecrypt}\nrpgmakerwantstodecrypt${rpgmakerWantsToDecrypt}`);
		if (((rpgmakerWantsToDecrypt) || force || (fs.existsSync(rpgMVPUrl) && !fs.existsSync(pngUrl))) && !MATTIE.compat.pauseDecrypt && !cannotUseEncrypted) {
			if (Utils.isNwjs()) {
				this._loadingState = 'decrypting';
				Decrypter.decryptImg(pngUrl, this);
				console.log(pngUrl);
				if (MATTIE.compat.runtime_decrypt) MATTIE.imageAPI.saveBitmapToFile(this, pngUrl);
				console.log('image decrypted');
			}
		} else if (pngUrl) {
		// this line will fix the issue with caching images and let us update files during runtime.
			fetch(url, { cache: 'reload', mode: 'no-cors' });

			// load image
			url.replace('.rpgmvp', '.png');
			this._image.src = url;
			this._image.addEventListener('load', this._loadListener = Bitmap.prototype._onLoad.bind(this));
			this._image.addEventListener('error', this._errorListener = this._loader || Bitmap.prototype._onError.bind(this));
		}
	} catch (error) {
		console.log(`caught error:${error}`);
	}
};

// override this so that when we request an image it will not try to decrypt it.
Bitmap.prototype._requestImage = function (url) {
	console.log(url);
	if (Bitmap._reuseImages.length !== 0) {
		this._image = Bitmap._reuseImages.pop();
	} else {
		this._image = new Image();
	}

	if (this._decodeAfterRequest && !this._loader) {
		this._loader = ResourceHandler.createLoader(url, this._requestImage.bind(this, url), this._onError.bind(this));
	}

	this._image = new Image();

	//---------------
	// very important
	//---------------

	this._url = url;
	this._loadingState = 'requesting';

	this.compatabilityLoad(url);
};

ImageManager.loadBitmap = function (folder, filename, hue, smooth, forceNoDecrypt = false) {
	// this is a hacky soltion but should work fine for now
	if (forceNoDecrypt) MATTIE.compat.pauseDecrypt = true;
	setTimeout(() => {
		MATTIE.compat.pauseDecrypt = false;
	}, 1000);
	if (filename) {
		const path = `${folder + encodeURIComponent(filename)}.png`;

		const bitmap = this.loadNormalBitmap(path, hue || 0);
		bitmap.smooth = smooth;
		return bitmap;
	}
	return this.loadEmptyBitmap();
};

/**
 * @description we override this such that it will not return an undefined result ever. Even if another mod fucks up
 * @todo I don't like this way of fixing this bug but does work.
 * @param unsafe, if true does not add anything
 * @returns {Game_Map} the datamap event obj
 */
MATTIE_RPG.Game_Event_Event = Game_Event.prototype.event;
Game_Event.prototype.event = function () {
	let val = MATTIE_RPG.Game_Event_Event.call(this);
	if (!val) val = $dataMap.events[1];
	if (!val) val = new MapEvent().data;
	return val;
};

//------------------------------
// Termina Compatibility
//------------------------------
var Olivia = Olivia || false;
if (Olivia) {
	if (Olivia.AntiPlayerStress) {
		setTimeout(() => {
			Olivia.AntiPlayerStress.ProperErrorDisplay = false; // termina should use my error menu to
		}, 5000);
	}
}

//---------------------------------
// Engine Fixes
//---------------------------------

// this fixes the screen freeze

/**
 * Renders the stage to the game screen.
 *
 * @static
 * @method render
 * @param {Stage} stage The stage object to be rendered
 */
Graphics.render = function (stage) {
	if (this._skipCount <= 0) {
		const startTime = Date.now();
		if (stage) {
			this._renderer.render(stage);
			if (this._renderer.gl && this._renderer.gl.flush) {
				this._renderer.gl.flush();
			}
		}
		const endTime = Date.now();
		const elapsed = endTime - startTime;
		this._skipCount = Math.min(Math.floor(elapsed / 15), this._maxSkip);
		this._rendered = true;
	} else {
		this._skipCount--;
		this._rendered = false;
	}
	this.frameCount++;
};

Window_EquipItem.prototype.includes = function (item) {
	if (item === null || typeof item === 'undefined') {
		return true;
	}
	if (this._slotId < 0 || item.etypeId !== this._actor.equipSlots()[this._slotId]) {
		return false;
	}
	return this._actor.canEquip(item);
};

/**
 * @override
 * @description
 * we override this method to return an empty bit map if one does not exist, that way if something calls this before the bit map is initialized
 * it won't error and give time for this to init hopefully.
 * The bitmap used for the window contents.
 *
 * @property contents
 * @type Bitmap
 */
Object.defineProperty(Window.prototype, 'contents', {
	get() {
		return this._windowContentsSprite ? this._windowContentsSprite.bitmap : ImageManager.loadEmptyBitmap();
	},
	set(value) {
		if (this._windowContentsSprite) this._windowContentsSprite.bitmap = value;
	},
	configurable: true,
});

/**
 * @override
 * @description override this method the hopefully fix https://itch.io/post/8679462
 *
 */
MATTIE.compat.createLayerGraphics = Spriteset_Map.prototype.createLayerGraphics;
Spriteset_Map.prototype.createLayerGraphics = function () {
	this.layerGraphics = this.layerGraphics || {};
	MATTIE.compat.createLayerGraphics.call(this);
};
// FIX non existant items from loading other mods
Game_Party.prototype.items = function () {
	var list = [];
	for (var id in this._items) {
		if ($dataItems[id]) { list.push($dataItems[id]); }
	}
	return list;
};

Game_Party.prototype.weapons = function () {
	var list = [];
	for (var id in this._weapons) {
		if ($dataWeapons[id]) list.push($dataWeapons[id]);
	}
	return list;
};

Game_Party.prototype.armors = function () {
	var list = [];
	for (var id in this._armors) {
		if ($dataArmors[id]) list.push($dataArmors[id]);
	}
	return list;
};

//-----------------------------------------
// fixes the gitpixel not defined bug
//-----------------------------------------
Window_Base.prototype.textColor = function (n) {
	var px = 96 + (n % 8) * 12 + 6;
	var py = 144 + Math.floor(n / 8) * 12 + 6;
	const bitMap = this.windowskin || new Bitmap(px + 2, py + 2);
	return bitMap.getPixel(px, py);
};

Window_Base.prototype.pendingColor = function () {
	const bitMap = this.windowskin || new Bitmap(120 + 2, 120 + 2);
	return bitMap.getPixel(120, 120);
};

Game_Character.prototype.updateRoutineMove = function () {
	if (this._waitCount > 0) {
		this._waitCount--;
	} else {
		this.setMovementSuccess(true);
		if (this._moveRoute) {
			var command = this._moveRoute.list[this._moveRouteIndex];
			if (command) {
				this.processMoveCommand(command);
				this.advanceMoveRouteIndex();
			}
		}
	}
};