/*
 * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight)
 * by the Epic Fight Team, licensed under GPLv3.
 * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
 */

package com.tiedup.remake.rig.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.function.Supplier;

import com.google.common.collect.Lists;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import it.unimi.dsi.fastutil.doubles.DoubleList;
import it.unimi.dsi.fastutil.floats.FloatArrayList;
import it.unimi.dsi.fastutil.floats.FloatList;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.world.phys.Vec3;
import com.tiedup.remake.rig.math.Vec3f;

public class ParseUtil {
	public static Integer[] toIntArray(JsonArray array) {
		List<Integer> result = Lists.newArrayList();

		for (JsonElement je : array) {
			result.add(je.getAsInt());
		}

		return result.toArray(new Integer[0]);
	}

	public static Float[] toFloatArray(JsonArray array) {
		List<Float> result = Lists.newArrayList();

		for (JsonElement je : array) {
			result.add(je.getAsFloat());
		}

		return result.toArray(new Float[0]);
	}

	public static int[] toIntArrayPrimitive(JsonArray array) {
		IntList result = new IntArrayList();

		for (JsonElement je : array) {
			result.add(je.getAsInt());
		}

		return result.toIntArray();
	}

	public static float[] toFloatArrayPrimitive(JsonArray array) {
		FloatList result = new FloatArrayList();

		for (JsonElement je : array) {
			result.add(je.getAsFloat());
		}

		return result.toFloatArray();
	}

	public static int[] unwrapIntWrapperArray(Number[] wrapperArray) {
		int[] iarray = new int[wrapperArray.length];

		for (int i = 0; i < wrapperArray.length; i++) {
			iarray[i] = (int)wrapperArray[i];
		}

		return iarray;
	}

	public static float[] unwrapFloatWrapperArray(Number[] wrapperArray) {
		float[] farray = new float[wrapperArray.length];

		for (int i = 0; i < wrapperArray.length; i++) {
			farray[i] = (float)wrapperArray[i];
		}

		return farray;
	}

	public static JsonObject farrayToJsonObject(float[] array, int stride) {
		JsonObject jsonObject = new JsonObject();
		jsonObject.addProperty("stride", stride);
		jsonObject.addProperty("count", array.length / stride);
		JsonArray jsonArray = new JsonArray();

		for (float element : array) {
			jsonArray.add(element);
		}

		jsonObject.add("array", jsonArray);

		return jsonObject;
	}

	public static JsonObject iarrayToJsonObject(int[] array, int stride) {
		JsonObject jsonObject = new JsonObject();
		jsonObject.addProperty("stride", stride);
		jsonObject.addProperty("count", array.length / stride);
		JsonArray jsonArray = new JsonArray();

		for (int element : array) {
			jsonArray.add(element);
		}

		jsonObject.add("array", jsonArray);

		return jsonObject;
	}

	public static Vec3f toVector3f(JsonArray array) {
		float[] result = toFloatArrayPrimitive(array);

		if (result.length < 3) {
			throw new IllegalArgumentException("Requires more than 3 elements to convert into 3d vector.");
		}

		return new Vec3f(result[0], result[1], result[2]);
	}

	public static Vec3 toVector3d(JsonArray array) {
		DoubleList result = new DoubleArrayList();

		for (JsonElement je : array) {
			result.add(je.getAsDouble());
		}

		if (result.size() < 3) {
			throw new IllegalArgumentException("Requires more than 3 elements to convert into 3d vector.");
		}

		return new Vec3(result.getDouble(0), result.getDouble(1), result.getDouble(2));
	}

	@SuppressWarnings("unchecked")
	public static <T extends Tag> T getOrDefaultTag(CompoundTag compTag, String name, T tag) {
		if (compTag.contains(name)) {
			return (T)compTag.get(name);
		}

		compTag.put(name, tag);

		return tag;
	}

	public static <T extends Enum<T>> T enumValueOfOrNull(Class<T> enumCls, String enumName) {
		try {
			return Enum.valueOf(enumCls, enumName.toUpperCase(Locale.ROOT));
		} catch (IllegalArgumentException | NullPointerException e) {
			return null;
		}
	}

	public static String toLowerCase(String s) {
		return s.toLowerCase(Locale.ROOT);
	}

	public static String toUpperCase(String s) {
		return s.toUpperCase(Locale.ROOT);
	}

	public static String getBytesSHA256Hash(byte[] bytes) {
		String hashString = "";

		try {
			MessageDigest sh = MessageDigest.getInstance("SHA-256");
			sh.update(bytes);
			byte byteData[] = sh.digest();
			StringBuffer sb = new StringBuffer();

			for (int i = 0; i < byteData.length; i++) {
				sb.append(Integer.toString((byteData[i] & 0xFF) + 0x100, 16).substring(1));
			}

			hashString = sb.toString();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			hashString = null;
		}

		return hashString;
	}

	public static <T> T orElse(T value, Supplier<T> defaultVal) {
		Objects.requireNonNull(defaultVal);

		return value == null ? defaultVal.get() : value;
	}

	private ParseUtil() {}
}
