package cc.util.bossshop;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;

/**
 * 一个用于获取NMS类的类
 * @author 聪聪
 *
 */
public class NMSHelper{

    /**
     * NMS类
     */
    public static final Class<?> clazz_EntityPlayerMP;
    public static final Class<?> clazz_EntityPlayer;
    public static final Class<?> clazz_NMSItemStack;
    public static final Class<?> clazz_NMSWorld;
    public static final Class<?> clazz_IInventory;
    public static final Class<?> clazz_NBTBase;
    public static final Class<?> clazz_NBTTagByte;
    public static final Class<?> clazz_NBTTagShort;
    public static final Class<?> clazz_NBTTagInt;
    public static final Class<?> clazz_NBTTagLong;
    public static final Class<?> clazz_NBTTagFloat;
    public static final Class<?> clazz_NBTTagDouble;
    public static final Class<?> clazz_NBTTagByteArray;
    public static final Class<?> clazz_NBTTagString;
    public static final Class<?> clazz_NBTTagIntArray;
    public static final Class<?> clazz_NBTTagList;
    public static final Class<?> clazz_NBTTagCompound;
    public static final Method method_CraftItemStack_asNMSCopy;
    public static final Method method_CraftItemStack_asCraftMirror;
    public static final Method method_CraftPlayer_getHandle;
    public static final Method method_NMSItemStack_getTag;
    //public static final Method method_NMSItemStack_setTag;//此方法歧义较大不建议启用
    public static final Method method_NBTTagCompound_isEmpty;
    public static final Method method_NBTTagCompound_clone;
    public static final Method method_NBTTagCompound_set;
    public static final Method method_NBTTagList_add;
    public static final Field field_NBTTagString_value;
    public static final Field field_NBTTagByte_value;
    public static final Field field_NBTTagShort_value;
    public static final Field field_NBTTagInt_value;
    public static final Field field_NBTTagFloat_value;
    public static final Field field_NBTTagDouble_value;
    public static final Field field_NBTTagLong_value;
    public static final Field field_NBTTagList_value;
    public static final Field field_NBTTagCompound_map;
    public static final Field field_NMSItemStack_tag;
    /**
     * CraftBukkit类
     */
    public static final Class<?> clazz_CraftItemStack;
    public static final Class<?> clazz_CraftInventory;
    public static final Class<?> clazz_CraftPlayer;

    static{
        String packetPath="";
        
        clazz_CraftItemStack=ClassHelper.getCBTClass("inventory.CraftItemStack");
        clazz_CraftInventory=ClassHelper.getCBTClass("inventory.CraftInventory");
        Method method_CraftInventory_getInventory=ClassHelper.getMethod(clazz_CraftInventory,"getInventory");
        clazz_IInventory=method_CraftInventory_getInventory.getReturnType();
        clazz_CraftPlayer=ClassHelper.getCBTClass("entity.CraftPlayer");
        method_CraftPlayer_getHandle=ClassHelper.getMethod(clazz_CraftPlayer,"getHandle");
        clazz_EntityPlayerMP=method_CraftPlayer_getHandle.getReturnType();
        clazz_EntityPlayer=clazz_EntityPlayerMP.getSuperclass();
        clazz_NMSWorld=clazz_EntityPlayer.getDeclaredConstructors()[0].getParameterTypes()[0];
        
        //NMS ItemStck
        ItemStack tItem=new ItemStack(Material.STONE);
        method_CraftItemStack_asNMSCopy=ClassHelper.getMethod(clazz_CraftItemStack,"asNMSCopy",ItemStack.class);
        Object tNMSItemStack_mcitem=ClassHelper.invokeStaticMethod(method_CraftItemStack_asNMSCopy,tItem);
        clazz_NMSItemStack=tNMSItemStack_mcitem.getClass();
        method_NMSItemStack_getTag=ClassHelper.getUnknowMethod(clazz_NMSItemStack,"NBTTagCompound").get(0);

        //NBT
        clazz_NBTTagCompound=method_NMSItemStack_getTag.getReturnType();
        packetPath=NMSHelper.getClassPrefix(clazz_NBTTagCompound.getName());
        clazz_NBTBase=ClassHelper.getClass(packetPath+"NBTBase");
        clazz_NBTTagByte=ClassHelper.getClass(packetPath+"NBTTagByte");
        clazz_NBTTagShort=ClassHelper.getClass(packetPath+"NBTTagShort");
        clazz_NBTTagInt=ClassHelper.getClass(packetPath+"NBTTagInt");
        clazz_NBTTagLong=ClassHelper.getClass(packetPath+"NBTTagLong");
        clazz_NBTTagFloat=ClassHelper.getClass(packetPath+"NBTTagFloat");
        clazz_NBTTagDouble=ClassHelper.getClass(packetPath+"NBTTagDouble");
        clazz_NBTTagByteArray=ClassHelper.getClass(packetPath+"NBTTagByteArray");
        clazz_NBTTagString=ClassHelper.getClass(packetPath+"NBTTagString");
        clazz_NBTTagIntArray=ClassHelper.getClass(packetPath+"NBTTagIntArray");
        clazz_NBTTagList=ClassHelper.getClass(packetPath+"NBTTagList");
        
        method_NBTTagCompound_isEmpty=ClassHelper.getUnknowMethod(clazz_NBTTagCompound,boolean.class).get(0);
        method_NBTTagCompound_clone=ClassHelper.getUnknowMethod(clazz_NBTTagCompound,clazz_NBTBase).get(0);
        method_NBTTagCompound_set=ClassHelper.getUnknowMethod(clazz_NBTTagCompound,void.class,new Class<?>[]{String.class,clazz_NBTBase}).get(0);
        method_CraftItemStack_asCraftMirror=ClassHelper.getMethod(clazz_CraftItemStack,"asCraftMirror",clazz_NMSItemStack);
        method_NBTTagList_add=ClassHelper.getUnknowMethod(clazz_NBTTagList,void.class,clazz_NBTBase).get(0);
        
        field_NBTTagByte_value=ClassHelper.getField(clazz_NBTTagByte,byte.class,-1).get(0);
        field_NBTTagShort_value=ClassHelper.getField(clazz_NBTTagShort,short.class,-1).get(0);
        field_NBTTagInt_value=ClassHelper.getField(clazz_NBTTagInt,int.class,-1).get(0);
        field_NBTTagFloat_value=ClassHelper.getField(clazz_NBTTagFloat,float.class,-1).get(0);
        field_NBTTagDouble_value=ClassHelper.getField(clazz_NBTTagDouble,double.class,-1).get(0);
        field_NBTTagLong_value=ClassHelper.getField(clazz_NBTTagLong,long.class,-1).get(0);
        field_NBTTagString_value=ClassHelper.getField(clazz_NBTTagString,String.class,Modifier.PRIVATE).get(0);
        field_NBTTagList_value=ClassHelper.getField(clazz_NBTTagList,List.class,-1).get(0);
        field_NBTTagCompound_map=ClassHelper.getField(clazz_NBTTagCompound,Map.class,-1).get(0);
        field_NMSItemStack_tag=ClassHelper.getField(clazz_NMSItemStack,clazz_NBTTagCompound,-1).get(0);

    }

    /**
     * 获取类全名的前段字符串
     * @param classFullName
     * @return
     */
    public static String getClassPrefix(String classFullName){
        String packetPath="";
        int pos=-1;
        if((pos=classFullName.lastIndexOf("."))!=-1)
            packetPath=classFullName.substring(0,pos+1);
        return packetPath;
    }
    
    public static Set<String> getNBTFirstDeepNodeList(ItemStack pItem){
        Object nbtTag=getNBTTagCompound(pItem);
        if(nbtTag==null) return null;
        Map<String,Object> tMap=getNBTTagMapFromTag(nbtTag);
        Set<String> rSet=new HashSet<>();
        for(String skey : tMap.keySet())
            rSet.add(skey);
        return rSet;
    }

    /**
     * 获取Bukkit物品的NBT标签
     * @param pItem Bukkit物品实例
     * @return NBTTagCompound实例或者null
     */
    public static Object getNBTTagCompound(ItemStack pItem){
        Object nmsItem=NMSHelper.getNMSItem(pItem);
        if(nmsItem==null) return null;
        return ClassHelper.invokeMethod(nmsItem,method_NMSItemStack_getTag);
    }
    
    /**
     * 获取物品的NBT的的值域Map
     * @param pItem 物品,可以为null
     * @return 可能为null
     */
    public static Map<String,Object> getNBTTagMapFromItem(ItemStack pItem){
        return getNBTTagMapFromTag(getNBTTagCompound(pItem));
    }
    
    /**
     * 获取Bukkit物品对应的MC物品
     * @param pItem Bukkit物品实例
     * @return NBTTagCompound实例或者null
     */
    public static Object getNMSItem(ItemStack pItem){
        if(pItem==null||pItem.getType()==Material.AIR) return null;
        return ClassHelper.invokeStaticMethod(method_CraftItemStack_asNMSCopy,pItem);
    }

    /**
     * 获取类类型为NBTTagCompound的值域Map
     * @param pNBTTagCompound 实例,类型必须为NBTTagCompound,可以为null
     * @return 可能为非null
     */
    public static Map<String,Object> getNBTTagMapFromTag(Object pNBTTagCompound){
        if(pNBTTagCompound==null) return new HashMap<>();
        return (Map<String,Object>)ClassHelper.getFieldValue(pNBTTagCompound,field_NBTTagCompound_map);
    }
   
    /**
     * 从NBTTagCompound实例中移除指定的标签
     * @param pNBTTagCompound NBTTagCompound实例
     * @param pNBTLabel NBT标签
     * @return 移除的值或null
     */
    public static Object removeFromNBTTagCompound(Object pNBTTagCompound,String pNBTLabel){
        Map<String,Object> tMap=NMSHelper.getNBTTagMapFromTag(pNBTTagCompound);
        if(tMap==null) return null;
        return tMap.remove(pNBTLabel);
    }    
    
    /**
     * 获取获取物品的Json字符串
     */
    public static String getItemJson(ItemStack pItem){
        if(pItem==null||pItem.getType()==Material.AIR) return "{}";
        String itemJson="{";
        itemJson+="id:"+pItem.getTypeId();
        itemJson+=",Damage:"+pItem.getDurability();
        Object tagNBTTagCompound=getNBTTagCompound(pItem);
        if(tagNBTTagCompound!=null) itemJson+=",tag:"+getNBTBaseValue(tagNBTTagCompound);
        itemJson+="}";
        return itemJson;
    }
    
    /**
     * 获取NBTBase的子类的Json值
     * <p>
     * 只对NBTTagString的toString方法重写<br />
     * 其他方法不变
     * </p>
     * @param pNBTBase
     * @return json字符串
     */
    public static String getNBTBaseValue(Object pNBTBase){
        if(pNBTBase==null) return "";
        if(NMSHelper.clazz_NBTTagCompound.isInstance(pNBTBase)){
            Map<String,Object> tNBTContents=(Map<String,Object>)ClassHelper.getFieldValue(pNBTBase,NMSHelper.field_NBTTagCompound_map);
            if(tNBTContents==null||tNBTContents.isEmpty()) return "{}";
            String contentJson = "{";
            for (String sKey : tNBTContents.keySet()) {
                Object tContentNode=tNBTContents.get(sKey);
                if(tContentNode==null) continue;
                contentJson+=sKey+':'+getNBTBaseValue(tContentNode)+',';
            }
            if(contentJson.lastIndexOf(",")!=-1)
                contentJson=contentJson.substring(0,contentJson.length()-1);
            return contentJson + "}";
        }else if(NMSHelper.clazz_NBTTagList.isInstance(pNBTBase)){
            List<Object> tNBTContents=(List<Object>)ClassHelper.getFieldValue(pNBTBase,NMSHelper.field_NBTTagList_value);
            if(tNBTContents==null||tNBTContents.isEmpty()) return "[]";
            String contentJson = "[";
            int i=0;
            for(Object tContentNode : tNBTContents){
                if(tContentNode==null) continue;
                contentJson+=i+":"+getNBTBaseValue(tContentNode).toString()+',';
                i++;
            }
            if(contentJson.lastIndexOf(",")!=-1)
                contentJson=contentJson.substring(0,contentJson.length()-1);
            return contentJson+"]";
        }else if(NMSHelper.clazz_NBTTagString.isInstance(pNBTBase)){
            String value=(String)ClassHelper.getFieldValue(pNBTBase,NMSHelper.field_NBTTagString_value);
            value=value.replace("\"","\\\"");
            return "\""+value+"\"";
        }else return pNBTBase.toString();
    }
    
}
