using System;
using System.Collections.Generic;
using System.Reflection.Emit;
using HarmonyLib;
using UnityEngine;

namespace DavesPhatStore {
	[HarmonyPatch]
	public class AutoPricer {
		// This does not work as I would like it to
		// We'll have to do it differently...
		// [HarmonyTranspiler]
		// [HarmonyPatch(typeof(PlayerNetwork), "Update")]
		// static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) {
		// 	Console.WriteLine("Transpiling PlayerNetwork.Update");
		// 	var codes = new List<CodeInstruction>(instructions);

		// 	for (int i = 0; i < codes.Count; i++) {
		// 		var codeInstruction = codes[i];
		// 		if (codeInstruction.operand == null) {
		// 			Console.WriteLine($"{i}: '{codeInstruction.opcode}' '{codeInstruction.operand}'");
		// 			continue;
		// 		}
		// 		Console.WriteLine($"{i}: '{codeInstruction.opcode}' '{codeInstruction.operand}' ('{codeInstruction.operand.GetType()}')");
		// 	}

		// 	int beqLoc = -1;
		// 	int startMove = -1;
		// 	int endMove = -1;
		// 	bool part1 = false;

		// 	for (int i = 0; i < codes.Count; i++) {
		// 		if (codes[i].opcode == OpCodes.Beq) {
		// 			beqLoc = i;
		// 			break;
		// 		}
		// 	}

		// 	for (int i = 0; i < codes.Count; i++) {
		// 		if (codes[i].opcode == OpCodes.Ldfld
		// 		&& codes[i].operand.ToString() == "System.Single[] tierInflation") {
		// 			startMove = i - 1;
		// 		}
		// 		if (startMove != -1
		// 		&& codes[i].opcode == OpCodes.Stloc_S
		// 		&& codes[i].operand.ToString() == "System.Single (24)"
		// 		&& codes[i - 1].opcode == OpCodes.Div) {
		// 			endMove = i;
		// 			break;
		// 		}
		// 	}

		// 	if (beqLoc != -1 && startMove != -1 && endMove != -1) {
		// 		Console.WriteLine($"Moving {endMove - startMove + 1} instructions from {startMove} to {beqLoc}");
		// 		List<CodeInstruction> blockToMove = codes.GetRange(startMove, endMove - startMove + 1);
		// 		codes.RemoveRange(startMove, endMove - startMove + 1);
		// 		codes.InsertRange(beqLoc, blockToMove);
		// 		part1 = true;
		// 	}

		// 	if (!part1) {
		// 		Console.WriteLine("Failed mvoing local variables above BEQ, bailing");
		// 		return new List<CodeInstruction>(instructions);
		// 	}

		// 	CodeInstruction savedStfld = null;
		// 	CodeInstruction savedLdloc = null;

		// 	for (int rep = 0; rep < 2; rep++) {
		// 		int start = -1, end = -1;
		// 		for (int i = 2; i < codes.Count; i++) {
		// 			var codeInstruction = codes[i];

		// 			if (savedLdloc == null
		// 			&& codeInstruction.opcode == OpCodes.Ldloc_S
		// 			&& codeInstruction.operand.ToString() == "System.Single (24)") {
		// 				savedLdloc = codeInstruction;
		// 			}

		// 			if (codeInstruction.opcode == OpCodes.Stfld
		// 			&& codeInstruction.operand.ToString() == "System.Single pPrice"
		// 			&& codes[i - 1].opcode != OpCodes.Call
		// 			&& codes[i - 2].opcode == OpCodes.Ldc_R4) {
		// 				savedStfld = codeInstruction;
		// 				end = i;
		// 				for (int j = i; j > Math.Max(0, i - 20); j--) {
		// 					if (codes[j].opcode == OpCodes.Ldarg_0
		// 					&& codes[j + 1].opcode == OpCodes.Ldarg_0) {
		// 						start = j;
		// 						break;
		// 					}
		// 				}
		// 			}

		// 			if (start != -1 && end != -1) {
		// 				Console.WriteLine("Start: " + start + ", End: " + end);
		// 				if (savedStfld == null) {
		// 					Console.WriteLine("SavedStfld is null");
		// 					continue;
		// 				}
		// 				codes.RemoveRange(start, end - start + 1);
		// 				codes.Insert(start, new CodeInstruction(OpCodes.Ldarg_0));
		// 				codes.Insert(start + 1, savedLdloc);
		// 				codes.Insert(start + 2, new CodeInstruction(OpCodes.Ldc_R4, 2f));
		// 				codes.Insert(start + 3, new CodeInstruction(OpCodes.Mul));
		// 				codes.Insert(start + 4, savedStfld);
		// 				Console.WriteLine($"Patched set price to 2x at {start}");
		// 				break;
		// 			}
		// 		}
		// 	}

		// 	for (int i = 0; i < codes.Count; i++) {
		// 		var codeInstruction = codes[i];
		// 		if (codeInstruction.operand == null) {
		// 			Console.WriteLine($"{i}: '{codeInstruction.opcode}' '{codeInstruction.operand}'");
		// 			continue;
		// 		}
		// 		Console.WriteLine($"{i}: '{codeInstruction.opcode}' '{codeInstruction.operand}' ('{codeInstruction.operand.GetType()}')");
		// 	}

		// 	return codes.AsEnumerable();
		// }

		[HarmonyPrefix]
		[HarmonyPatch(typeof(ProductListing), nameof(ProductListing.CmdUpdateProductPrice))]
		public static void CmdUpdateProductPricePrefix(ref int productID, ref float newPrice) {
			Console.WriteLine($"Called CmdUpdateProductPricePrefix with {productID} and {newPrice}");
			var inflationPrice = ProductListing.Instance.tierInflation[ProductListing.Instance.productPrefabs[productID].GetComponent<Data_Product>().productTier];
			float realPricePerUnit = ProductListing.Instance.productPrefabs[productID].GetComponent<Data_Product>().basePricePerUnit * inflationPrice;
			realPricePerUnit = Mathf.Round(realPricePerUnit * 100f) / 100f;
			newPrice = realPricePerUnit * Main.setPriceMultiplier.Value;
			Console.WriteLine($"Adjusted price to {newPrice} for product {productID}");
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(PlayerNetwork), "Update")]
		static IEnumerable<CodeInstruction> UpdateTranspiler(IEnumerable<CodeInstruction> instructions) {
			var codes = new List<CodeInstruction>(instructions);

			// for (int i = 0; i < codes.Count; i++) {
			// 	var codeInstruction = codes[i];
			// 	if (codeInstruction.operand == null) {
			// 		Console.WriteLine($"{i}: '{codeInstruction.opcode}' '{codeInstruction.operand}'");
			// 		continue;
			// 	}
			// 	Console.WriteLine($"{i}: '{codeInstruction.opcode}' '{codeInstruction.operand}' ('{codeInstruction.operand.GetType()}')");
			// }

			int start = 0, end = 0;
			for (int i = 0; i < codes.Count; ++i) {
				if (codes[i].opcode == OpCodes.Brfalse
				&& codes[i + 1].opcode == OpCodes.Ldsfld
				&& codes[i + 2].opcode == OpCodes.Ldfld
				&& codes[i + 2].operand.ToString().Equals("System.Single[] productPlayerPricing")) {
					start = i;
				}

				if (codes[i].opcode == OpCodes.Beq
				&& codes[i - 1].opcode == OpCodes.Ldfld
				&& codes[i - 2].opcode == OpCodes.Ldarg_0
				&& codes[i - 1].operand.ToString().Equals("System.Single pPrice")) {
					end = i;
					break;
				}
			}
			Console.WriteLine($"Found UpdateTranspiler start at {start}, end at {end}");
			codes.RemoveRange(start, end - start + 1);
			
			return instructions;
		}
	}
}