package com.zivilon.cinder_loe.coremod;

import net.minecraft.launchwrapper.IClassTransformer;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;

import java.util.Iterator;

public class LOTRMaterialTransformer implements IClassTransformer {
    @Override
    public byte[] transform(String name, String transformedName, byte[] classBytes) {
        if (transformedName.equals("lotr.common.item.LOTRMaterial")) {
            System.out.println("[CinderLoE] Transforming LOTRMaterial...");

            ClassReader reader = new ClassReader(classBytes);
            ClassNode classNode = new ClassNode();
            reader.accept(classNode, 0);


            modifyMaterial("ANGMAR", 350, 0.6F, 2.5F, classNode); //Original Durability = 350 | Add 81 | 162 if Upgraded Armory | 1/4 (Unupgraded)
            modifyMaterial("URUK", 550, 0.7F, 3.0F, classNode); //Original Durability = 550 | Add 56 | 112 if Upgraded Armory | 1/4 (Unupgraded)
            modifyMaterial("BLACK_URUK", 550, 0.7F, 3.0F, classNode); //Original Durability = 550 | Add 56 | 112 if Upgraded Armory | 2/4 (Unupgraded)
            modifyMaterial("HALF_TROLL", 350, 0.6F, 2.5F, classNode); //Original Durability = 300 | Add 87 | 175 if Upgraded Armory | 1/4 (Unupgraded)

            // Good Humans
            modifyMaterial("DALE", 350, 0.6F, 2.5F, classNode); //Original Durability = 300 | Add 87 | 175 if Upgraded Armory | 1/4 (Unupgraded)
            modifyMaterial("GONDOR", 450, 0.6F, 2.5F, classNode); //Original Durability = 450 | Add 68 | 137 if Upgraded Armory | 3/4 (Unupgraded)
            modifyMaterial("DORWINION_ELF", 500, 0.6F, 3.0F, classNode); //Original Durability = 500 | Add 62 | 125 if Upgraded Armory | 3/4 (Unupgraded)
            modifyMaterial("ROHAN", 350, 0.6F, 2.5F, classNode); //Original Durability = 300 | Add 87 | 175 if Upgraded Armory | 0/4
            modifyMaterial("TAUREDAIN", 350, 0.6F, 2.5F, classNode); //Original Durability = 300 | Add 87 | 175 if Upgraded Armory | 0/4
            modifyMaterial("DORWINION", 400, 0.6F, 2.5F, classNode); //Original Durability = 400 | Add 75 | 150 if Upgraded Armory | 0/4
            modifyMaterial("LOSSARNACH", 350, 0.6F, 2.5F, classNode); //Original Durability = 300 | Add 87 | 175 if Upgraded Armory  0/4
            modifyMaterial("LAMEDON", 350, 0.6F, 2.0F, classNode); //Original Durability = 300 | Add 87 | 175 if Upgraded Armory | 0/4


            // Evil Humans
            modifyMaterial("RHUN_GOLD", 450, 0.6F, 2.5F, classNode); //Original Durability = 450 | Add 68 | 137 if Upgraded Armory | 0/4
            modifyMaterial("RHUN", 400, 0.6F, 2.5F, classNode); //Original Durability = 400 | Add 75 | 150 if Upgraded Armory | 0/4
            modifyMaterial("DUNLENDING", 350, 0.6F, 2.0F, classNode); //Original Durability = 250 | Add 93 | 187 if Upgraded Armory | 1/4 (Unupgraded)
            modifyMaterial("NEAR_HARAD", 450, 0.6F, 2.5F, classNode); //Original Durability = 300 | Add 87 | 175 if Upgraded Armory | 3/4 (Unupgraded)
            modifyMaterial("HARNEDOR", 350, 0.6F, 2.0F, classNode); //Original Durability = 250 | Add 93 | 187 if Upgraded Armory | 0/4
            modifyMaterial("CORSAIR", 350, 0.6F, 2.5F, classNode); //Original Durability = 300 | Add 87 | 175 if Upgraded Armory | 0/4
            modifyMaterial("GULF_HARAD", 350, 0.6F, 2.5F, classNode); //Original Durability = 350 | Add 81 | 162 if Upgraded Armory | 0/4
            modifyMaterial("UMBAR", 450, 0.6F, 2.5F, classNode); //Original Durability = 450 | Add 68 | 137 if Upgraded Armory | 2/4 (Unupgraded)
            modifyMaterial("MOREDAIN", 350, 0.6F, 2.0F, classNode); //Original Durability = 250 | Add 93 | 187 if Upgraded Armory | 0/4

            //Elves
            modifyMaterial("WOOD_ELVEN", 500, 0.6F, 3.0F, classNode); //Original Durability = 500 | Add 62 | 125 if Upgraded Armory | 4/4 (Unupgraded)

            // Custom
            modifyMaterial("UTUMNO", 1500, 0.7F, 3.5F, classNode);
            modifyMaterial("GONDOLIN", 1500, 0.7F, 4.0F, classNode);

            addMaterial("RED_DWARF", classNode);
            addMaterial("WIZARD", classNode);
            addMaterial("LIMWAITH_BONE", classNode);
            addMaterial("BONEMOLD", classNode);
            addMaterial("LIMWAITH_WOOD", classNode);
            addMaterial("EVENT", classNode);
            addMaterial("BREE", classNode);
            addMaterial("BATTLENUN", classNode);
            addMaterial("ASH", classNode);
            addMaterial("RHUDAUR", classNode);
            addMaterial("SERPENT", classNode);
            addMaterial("USURPER", classNode);
            addMaterial("WARLORD",classNode);
            addMaterial("ESGAROTH",classNode);
            addMaterial("DORWINIONELITE",classNode);
            addMaterial("JADE",classNode);
            addMaterial("GILDEDGALVORN",classNode);
            addMaterial("ARTIFACT",classNode);
            addMaterial("SUNLIT_WARDEN",classNode);
            addMaterial("ORTHANC_GUARD",classNode);

            // Protection Conversion

            // Convert your ClassNode back to byte array with ClassWriter
            ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
            classNode.accept(writer);

            byte[] transformedBytes = writer.toByteArray();
            return transformedBytes;
        }
        return classBytes;
    }

    public void addMaterial(String fieldName, ClassNode classNode) {
        FieldNode field = new FieldNode(
            Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC,
            fieldName,
            "Llotr/common/item/LOTRMaterial;", // Adjust the descriptor based on the actual package name
            null,
            null
        );
        classNode.fields.add(field);
    }

    public void modifyMaterial(String fieldName, int durability, float protection, float weapon_damage, ClassNode classNode) {
        MethodNode clinit = null;
        boolean foundField = false;
        boolean durabilityModified = false;
        boolean protectionModified = false;
        boolean damageModified = false;

        // First, find the <clinit> method
        for (MethodNode method : classNode.methods) {
            if (method.name.equals("<clinit>")) {
                clinit = method;
                break;
            }
        }

        if (clinit == null) {
            return;
        }


        Iterator<AbstractInsnNode> iter = clinit.instructions.iterator();
        while (iter.hasNext()) {
            AbstractInsnNode insn = iter.next();

            if (insn instanceof LdcInsnNode && ((LdcInsnNode) insn).cst.equals(fieldName)) {
                foundField = true;
            }
            if (foundField && insn instanceof MethodInsnNode && ((MethodInsnNode) insn).name.equals("setProtection")) {
                AbstractInsnNode protectionInsn = insn.getPrevious();

                if (protectionInsn instanceof LdcInsnNode) {
                    ((LdcInsnNode) protectionInsn).cst = protection;
                    System.out.println("[CinderLoE] Updated protection for " + fieldName + " to " + protection);
                    return;
                }
            }

            if (foundField && !durabilityModified && insn instanceof MethodInsnNode && ((MethodInsnNode) insn).name.equals("setUses")) {
                AbstractInsnNode durabilityInsn = insn.getPrevious();

                if (durabilityInsn instanceof IntInsnNode) {
                    ((IntInsnNode) durabilityInsn).operand = durability;
                    System.out.println("[CinderLoE] Updated durability for " + fieldName + " to " + durability);
                    durabilityModified = true;
                }
            }

            if (foundField && !protectionModified && insn instanceof MethodInsnNode && ((MethodInsnNode) insn).name.equals("setProtection")) {
                AbstractInsnNode protectionInsn = insn.getPrevious();

                if (protectionInsn instanceof LdcInsnNode) {
                    ((LdcInsnNode) protectionInsn).cst = protection;
                    System.out.println("[CinderLoE] Updated protection for " + fieldName + " to " + protection);
                    protectionModified = true;
                }
            }

            if (foundField && !damageModified && insn instanceof MethodInsnNode && ((MethodInsnNode) insn).name.equals("setDamage")) {
                AbstractInsnNode damage_insn = insn.getPrevious();

                if (damage_insn instanceof LdcInsnNode) {
                    ((LdcInsnNode) damage_insn).cst = weapon_damage;
                    System.out.println("[CinderLoE] Updated damage for " + fieldName + " to " + weapon_damage);
                    damageModified = true;
                }
            }

            if (durabilityModified && protectionModified && damageModified) {
                return;
            }
        }

        if (!foundField) {
            System.out.println("[CinderLoE] Field '" + fieldName + "' not found in <clinit>.");
        }
    }
}
