package com.yheriatovych.reductor;

import com.yheriatovych.reductor.annotations.ActionCreator;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;

public class Actions {
    private static ConcurrentHashMap<Class<?>, Object> classCache = new ConcurrentHashMap<>();

    public static <T> T creator(Class<T> actionCreator) {
        Object creator = classCache.get(actionCreator);
        if (creator == null) {
            creator = createCreator(actionCreator);
            classCache.put(actionCreator, creator);
        }
        return (T) creator;
    }

    private static Object createCreator(Class<?> actionCreator) {
        String className = actionCreator.getName();
        String generatedActionCreator = className + "_AutoImpl";

        try {
            Class<?> generatedClass = Class.forName(generatedActionCreator);
            return generatedClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            //should not happen with auto generated classes
            throw new IllegalStateException(e);
        } catch (ClassNotFoundException e) {
            //if there are not generated action creators just fallback to dynamic proxy
            return createDynamicProxy(actionCreator);
        }
    }

    private static Object createDynamicProxy(Class<?> actionCreator) {
        //TODO validate

        Method[] methods = actionCreator.getMethods();
        final HashMap<Method, String> actionsMap = new HashMap<>(methods.length);
        for (Method method : methods) {
            ActionCreator.Action annotation = method.getAnnotation(ActionCreator.Action.class);
            if (annotation == null) {
                throw new IllegalStateException(
                        String.format("Method %s should be annotated with @%s",
                                method, ActionCreator.Action.class.getCanonicalName()));
            }
            actionsMap.put(method, annotation.value());
        }
        return Proxy.newProxyInstance(actionCreator.getClassLoader(), new Class<?>[]{actionCreator},
                (instance, method, args) -> {
                    String action = actionsMap.get(method);
                    if(args == null){
                        args = new Object[0];
                    }
                    return new Action(action, args);
                });
    }

}

@@ -909,32 +909,153 @@
 ActionCreator);%0A
+            //Ok, if class exists then it was generated by our annotation processor%0A            //so no need to validate%0A
             retu
@@ -1552,23 +1552,241 @@
     
-//TODO validate
+if(actionCreator.getAnnotation(ActionCreator.class) == null) %7B%0A            throw new IllegalStateException(String.format(%0A                    %22%25s should be interface annotated with %25s%22, actionCreator, ActionCreator.class));%0A        %7D
 %0A%0A  

validate in runtime that action creator has @ActionCreator annotation