package com.usenative;

import androidx.annotation.NonNull;

import com.facebook.react.bridge.*;
import com.facebook.react.module.annotations.ReactModule;

import java.lang.*;
import java.lang.reflect.*;
import java.util.*;
import android.widget.*;

import com.facebook.react.modules.core.*;
import android.app.*;

@ReactModule(name = UseNativeModule.NAME)
public class UseNativeModule extends ReactContextBaseJavaModule {
  public static final String NAME = "UseNative";

  public UseNativeModule(ReactApplicationContext reactContext) {
    super(reactContext);
  }

  @Override
  public void initialize(){
    try{
        ReactApplicationContext ctx=this.getReactApplicationContext();
        RJavaObjectManager.initSpecial("$app",new RJavaObject(ctx.getClass(),ctx));
        RJavaObjectManager.initSpecial("$appnative",new RJavaObject(Class.forName("android.content.Context"),ctx));
    }catch(Exception e){}
  }

  @Override
  @NonNull
  public String getName() {
    return NAME;
  }

  // 创建对象，返回对象变量内部名称
  @ReactMethod
  public void createJavaObject(String className,ReadableArray params,String packageName,Promise promise){
    String classFullName=className;
    if(!packageName.isEmpty()){
        classFullName=packageName+"."+className;
    }

    try{
        RJavaParamsHandler paramsHandler=new RJavaParamsHandler(getReactApplicationContext(),params);

        Class useClass=null;
        useClass=Class.forName(classFullName); // 找到类，只有非静态类才能创建实例
        Constructor useConstructor=useClass.getConstructor(paramsHandler.getParamsType()); // 得到构造器方法
        Object newIns=useConstructor.newInstance(paramsHandler.getParamsValue()); // 得到新创建的对象，并将其存储

        String newInsIntName=RJavaObjectManager.addInternal(new RJavaObject(useClass,newIns));

        promise.resolve(newInsIntName);

    }catch(ClassNotFoundException e){
        promise.reject("类没有找到异常"+e.getMessage());
    }catch(NoSuchMethodException e){
        promise.reject("没有此方法");
    }catch(IllegalAccessException e){
        promise.reject("没有权限异常"+e.getMessage());
    }catch(InvocationTargetException e){
        promise.reject("调用对象异常 在create中"+e.getMessage());
    }catch(Exception e){
        promise.reject("其它异常"+e.getMessage());
    }
  }

  @ReactMethod
  public void getJavaObjectValue(String objectName,Promise promise){
    // 通过RJavaObjectManager来获得存储的内部变量的值,可能是int等基本类型或包装类、或其它类类型，其它类返回"Reference type"
    try{
        Converter.promiseToJavaScript(objectName,promise);
    }catch(Exception e){

    }
  }

  // 获得Java中的数组或者List<T>中的某个值，List会通过内部变量存储，只需要获得
  @ReactMethod
  public void getJavaObjectArrayElement(String arrayIntName,int idx,String genericTypeName,Promise promise) throws Exception{
    // arrayIntName为存储的数组的内部名称,idx为数组中的索引，从0开始计算
    RJavaObject array=RJavaObjectManager.get(arrayIntName);
    Class arrayType=array.getType(); // 代表该数组的类型，可能是T[]、List<T>等
    Object arrayValue=array.getObject(); // 代表整个数组，它是一个Object[]类型

    Class elementType=null;
    Object elementValue=null;
    // 基本类型，作为数组时按原样存储，但是获得值之前需要先转换为包装类型，数组转换为Object[]    
    if(arrayType.isArray()){
        // 如果是数组，包括基本类型和引用类型
        if(arrayType==int[].class){
            // 基本类型数组转换，不包括List
            elementType=int.class;
            elementValue=((int[])arrayValue)[idx];
        }else if(arrayType==float[].class){
            elementType=int.class;
            elementValue=((float[])arrayValue)[idx];
        }else if(arrayType==boolean[].class){
            elementType=int.class;
            elementValue=((boolean[])arrayValue)[idx];
        }else if(arrayType==double[].class){
            elementType=int.class;
            elementValue=((double[])arrayValue)[idx];
        }else{
            // 引用类型数组转换
            elementType=arrayType.getComponentType(); // 每一个元素的类型
            elementValue=((Object[])arrayValue)[idx]; // 当前索引的值,存储进管理器中  
        }     
    }else{
        // List<T> 根据泛型
        if(!genericTypeName.isEmpty()){
            elementType=Class.forName(genericTypeName);
            elementValue=((List<Object>)arrayValue).get(idx);
        }else{
            // 暂不处理
            //handle=false;
        }
    }
    
    //if(handle!=false){
        String tmpIntName=RJavaObjectManager.addInternal(new RJavaObject(elementType,elementValue));
        Converter.promiseToJavaScript(tmpIntName,promise);
        RJavaObjectManager.remove(tmpIntName);
    //}

  }

  @ReactMethod
  public void getJavaObjectArrayLength(String objectName,Promise promise){
    // 返回数组长度
    RJavaObject array=RJavaObjectManager.get(objectName);
    Class arrayType=array.getType(); // 代表该数组的类型，可能是T[]、List<T>等
    Object arrayValue=array.getObject(); // 代表整个数组，它是一个Object[]类型

    // 基本类型，作为数组时按原样存储，但是获得值之前需要先转换为包装类型，数组转换为Object[]
    int ret=-1;    
    if(arrayType.isArray()){
        // 如果是数组，包括基本类型和引用类型
        if(arrayType==int[].class){
            // 基本类型数组转换，不包括List
            ret=((int[])arrayValue).length;
        }else if(arrayType==float[].class){
            ret=((float[])arrayValue).length;
        }else if(arrayType==boolean[].class){
            ret=((boolean[])arrayValue).length;
        }else if(arrayType==double[].class){
            ret=((double[])arrayValue).length;
        }else{
            // 引用类型数组转换
            ret=((Object[])arrayValue).length; // 当前索引的值,存储进管理器中
        }     
    }else{
        // List<T>
        ret=((List<Object>)arrayValue).size();
    }
    promise.resolve(ret);
  }

  // 调试之用
  @ReactMethod
  public void poolLength(Promise promise){
    // 返回RJavaObjectManager变量池中的变量的个数
    promise.resolve(RJavaObjectManager.size());
  }
  
  @ReactMethod 
  public void poolRemove(String intName){
    // 从变量池中删除某个变量
    RJavaObjectManager.remove(intName);
  }

  // 主要的调用方法
  @ReactMethod
    public void useJavaNative(String className,String methodName,ReadableArray params,String packageName,String objName,Promise promise){
        // 自v1.0.3开始，传递过来的每一个参数都是一个字符串
        try{
            // 参数转换处理
            String classFullName=className;

            if(!packageName.isEmpty()){
                classFullName=packageName+"."+classFullName;
            }

            // 参数类型转换处理，传递过来的参数都是Object类型，在params列表中
            RJavaParamsHandler paramsHandler=new RJavaParamsHandler(getReactApplicationContext(),params);
            Class[] paramsType=paramsHandler.getParamsType();
            Object[] paramsValue=paramsHandler.getParamsValue();            

            // 动态寻找类
            
            Class useClass;
            if(!className.isEmpty()){
              useClass=Class.forName(classFullName);
            }
            else{
              useClass=RJavaObjectManager.get(objName).getType();
            }


            Method useMethod=useClass.getMethod(methodName, paramsType);
            Class useMethodRetType=useMethod.getReturnType();

            Object useMethodObject=null; // 使用方法的对象，默认为null，即使用静态方法
            if(!objName.isEmpty()){
                // 调用实例方法，传入对象名称，通过管理器返回
                useMethodObject=RJavaObjectManager.get(objName).getObject();
            }

            Object methodReturnValue=useMethod.invoke(useMethodObject,paramsValue);
    
            // 返回值处理
            RJavaObject obj=new RJavaObject(useMethodRetType,methodReturnValue); // 将返回值作为一个内部变量存储
            String intName=RJavaObjectManager.addInternal(obj); // 返回一个内部名称

            promise.resolve(intName);
        }catch(ClassNotFoundException e){
            promise.reject("类没有找到异常"+e.getMessage());
        }catch(NoSuchMethodException e){
            promise.reject("方法没有找到异常"+e.getMessage());
        }catch(IllegalAccessException e){
            promise.reject("没有权限异常"+e.getMessage());
        }catch(InvocationTargetException e){
            promise.reject("内部抛出错误"+e.getCause().getMessage());
        }
    }

    // 得到某个类的父类
    @ReactMethod
    public void convertToParentClassObject(String objectName,Promise promise) throws Exception{
        Class findClass=null;
        Object storageValue=null;
        

        if(objectName.equals("$app")){
            ReactApplicationContext ctx=getReactApplicationContext();
            findClass=ctx.getClass().getSuperclass();
            storageValue=ctx;
        }else{
            findClass=RJavaObjectManager.get(objectName).getType().getSuperclass();
            storageValue=RJavaObjectManager.get(objectName).getObject();
        }

        String intName=RJavaObjectManager.addInternal(new RJavaObject(findClass,storageValue));
        promise.resolve(intName);
    }

    @ReactMethod
    public void castObject(String objectName,String className,Promise promise) throws Exception{
        // 将对象转换成某种类型，然后返回新对象的内部名称,objectName为对象名称、className为新的类的类名
        Object oldValue;
        Class newType;
        
        if(className.equals("String[]")){
            newType=String[].class;
        }
        else{
            newType=Class.forName(className);
        }
        
        if(objectName.equals("$app")){
            oldValue=getReactApplicationContext();
        }else{
            oldValue=RJavaObjectManager.get(objectName).getObject();    
        }
        
        Object newValue=newType.cast(oldValue);
        String newIntName=RJavaObjectManager.addInternal(new RJavaObject(newType,newValue));

        promise.resolve(newIntName);
    }

    @ReactMethod
    public void getJavaObjectType(String objectName,Promise promise){
        Class type=RJavaObjectManager.get(objectName).getType();
        promise.resolve(type.toString());
    }

    @ReactMethod
    public void createJavaArray(String elementClassName,int length,ReadableArray params,Promise promise) throws Exception{
        // params为数组的值
        Class eleType=Class.forName(elementClassName);
        Object arr=Array.newInstance(eleType,length);

        // 由于在Java中数组必须是同类型的
        RJavaParamsHandler handler=new RJavaParamsHandler(getReactApplicationContext(),params);
        Class[] elesType=handler.getParamsType(); // 数组的元素类型
        Object[] elesValue=handler.getParamsValue(); // 数组的值

        for(int i=0;i<elesType.length;i++){
            Class nowType=elesType[i];
            Object nowValue=elesValue[i];

            //if(nowType==Class.forName("java.lang.String")){

            //}
            Array.set(arr,i,nowValue);
        }

        String intName=RJavaObjectManager.addInternal(new RJavaObject(arr.getClass(),arr));
        promise.resolve(intName);
    }

    /*@ReactMethod
    public void setJavaObjectValue(String intName,String value){
        // 将非数组的元素设置为某个值，之后版本再更新
    }*/

    @ReactMethod
    public void getJavaCurrentActivity(Promise promise) throws Exception{
        Activity now=getCurrentActivity();

        RJavaObject storage=new RJavaObject(Class.forName("android.app.Activity"),now);
        String retName=RJavaObjectManager.addInternal(storage);

        promise.resolve(retName);
    }
}
