package com.zivilon.cindercore.mixins;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Dynamic;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.lang.reflect.Field;

import net.minecraft.item.ItemStack;

import com.zivilon.cindercore.network.PacketInterceptor;
import com.zivilon.cindercore.CinderCore;

import net.minecraft.entity.Entity;
import net.minecraft.entity.DataWatcher;

import lotr.common.item.LOTRItemBanner;
import lotr.common.entity.item.LOTREntityBanner;
import lotr.common.entity.item.LOTREntityBannerWall;

@Mixin(PacketInterceptor.class)
public abstract class LOTRPatches {

    @Inject(method = "process_custom_item_datavalue", at = @At("HEAD"), cancellable = true, remap = false)
    private void process(ItemStack item, UUID uuid, CallbackInfo ci) {
        System.out.println("Running process_custom_item_datavalue");
        int datavalue = item.getItemDamage();
        String item_name = item.getItem().getUnlocalizedName();
        if (item_name.equals("item.lotr:banner")) {
            Map<String, Map<Integer, Integer>> fallbacks = CinderCore.getCustomFallbackMap(uuid);
            Map<Integer, Integer> bannerFallbacks = fallbacks.get("banner"); 
            if (bannerFallbacks != null) {
                Integer replacementDataValue = bannerFallbacks.get(datavalue);
                if (replacementDataValue != null) {
                    item.setItemDamage(replacementDataValue);
                }
            }
        }
    }

    @Inject(method = "process_custom_item_datavalue_int", at = @At("HEAD"), cancellable = true, remap = false)
    private void process(int datavalue, String item_name, UUID uuid, CallbackInfoReturnable ci) {
        System.out.println("Running process_custom_item_datavalue_int");
        if (item_name.equals("item.lotr:banner")) {
            Map<String, Map<Integer, Integer>> fallbacks = CinderCore.getCustomFallbackMap(uuid);
            Map<Integer, Integer> bannerFallbacks = fallbacks.get("banner"); 
            if (bannerFallbacks != null) {
                Integer replacementDataValue = bannerFallbacks.get(datavalue);
                if (replacementDataValue != null) {
                    datavalue = replacementDataValue;
                }
            }
        }
    }
    @Inject(method = "process_custom_entity", at = @At("HEAD"), cancellable = true, remap = false)
    private static void process(Entity entity, UUID uuid, CallbackInfo ci) {
        System.out.println("Running process_custom_entity");
        if (entity == null) System.out.println("Entity is null");
        String class_name = entity.getClass().getName();
        System.out.println("[DEBUG] Entity class: " + class_name);
        DataWatcher dataWatcher = null;
        Field dataWatcherField = null;
        Class<?> currentClass = entity.getClass();
        while (currentClass != null) {
            try {
                dataWatcherField = currentClass.getDeclaredField("field_70180_af");
                dataWatcherField.setAccessible(true);
                break;
            } catch (NoSuchFieldException e) {
                if (currentClass.getSuperclass() == null) System.out.println("Superclass is null");
                currentClass = currentClass.getSuperclass();
            }
        }
        try {
            if (dataWatcherField == null) System.out.println("DataWatcherField is null");
            dataWatcher = (DataWatcher)dataWatcherField.get(entity);
        } catch (IllegalAccessException e) {
            System.err.println("IllegalAccessException" + e);
        }

        if (dataWatcher == null) System.out.println("DataWatcher is null");
        if (dataWatcher != null) System.out.println("DataWatcher is not null");

        if (entity instanceof LOTREntityBanner || entity instanceof LOTREntityBannerWall) {
            Map<String, Map<Integer, Integer>> fallbacks = CinderCore.getCustomFallbackMap(uuid);
            System.out.println("Got custom fallbacks list");
            Map<Integer, Integer> bannerFallbacks = fallbacks.get("banner");
            System.out.println("Got fallbacks list for banners");
            if (bannerFallbacks != null) {
                int originalBannerTypeID = dataWatcher.getWatchableObjectByte(18);;  
                Integer fallbackBannerTypeID = bannerFallbacks.get(originalBannerTypeID);

                if (fallbackBannerTypeID != null) {
                int id = fallbackBannerTypeID;
                    dataWatcher.updateObject(18, Byte.valueOf((byte)id));
                }
            }
        }
    }
    @Inject(method = "process_custom_entity_metadata", at = @At("HEAD"), cancellable = true, remap = false)
    private void process(Entity entity, int i, List<DataWatcher.WatchableObject> originalMetadata, UUID uuid, CallbackInfo ci) {
        System.out.println("Running process_custom_entity_metadata");
        System.out.println("Sending metadata of entity class " + entity.getClass().getName());
        DataWatcher.WatchableObject watchableObject = originalMetadata.get(i);
        DataWatcher.WatchableObject modifiedWatchableObject = new DataWatcher.WatchableObject(watchableObject.getObjectType(), watchableObject.getDataValueId(), watchableObject.getObject());
        Object obj = modifiedWatchableObject.getObject();

        Map<String, Map<Integer, Integer>> fallbacks = CinderCore.getCustomFallbackMap(uuid);

        if (entity != null && (entity instanceof LOTREntityBanner || entity instanceof LOTREntityBannerWall)) {
            Map<Integer, Integer> bannerFallbacks = fallbacks.get("banner"); 
            System.out.println("Passed banner get");
            if (bannerFallbacks != null) {
                System.out.println("Fallbacks are not null");
                if (obj instanceof Byte) {
                    System.out.println("Is byte");
                    Byte byteObj = (Byte) obj;
                    if (watchableObject.getDataValueId() == 18) {
                        System.out.println("Value is 18");
                        Integer fallbackBannerTypeID = bannerFallbacks.get((int)byteObj);
                        System.out.println("Fallback banner ID got: " + fallbackBannerTypeID);

                        if (fallbackBannerTypeID != null) {
                            System.out.println("Yes");
                            byteObj = (byte) fallbackBannerTypeID.byteValue();
                            modifiedWatchableObject.setObject(byteObj);                    
                        }
                    }
                }
            } else {
                if (obj instanceof Byte) {
                    Byte byteObj = (Byte) obj;
                    System.out.println("Getting watchable object ID to check if banner: " + watchableObject.getDataValueId() + " with value " + byteObj);
                }
            }
        }
        originalMetadata.set(i, modifiedWatchableObject);
    }
}

