package de.accso.flexinale.common.shared_kernel;

import de.accso.flexinale.common.api.event.Event;

import java.lang.reflect.Constructor;

import static de.accso.flexinale.common.shared_kernel.ClazzHelper.clazzImplementsInterface;

public final class EventClassHelper {
    @SuppressWarnings("unchecked")
    public static <E extends Event> Class<E> getClassFor(final String clazzName) {
        try {
            return (Class<E>) Class.forName(clazzName);
        }
        catch (ClassNotFoundException ex) {
            throw new FlexinaleIllegalStateException(ex);
        }
    }

    public static <E extends Event> String getEventClazzName(final String clazzName) {
        Class<? extends Event> clazz = getClassFor(clazzName);

        if (!clazzImplementsInterface(clazz, Event.class)) {
            throw new FlexinaleIllegalArgumentException("wrong clazz %s used to retrieve Event's clazz name and version"
                    .formatted(clazzName));
        }

        return clazz.getCanonicalName();
    }

    public static <E extends Event> String getEventClazzName(final Class<E> clazz) {
        return clazz.getCanonicalName();
    }

    public static <E extends Event> Versionable.Version getEventClazzVersion(String clazzName) {
        Class<? extends Event> clazz = getClassFor(clazzName);

        if (!clazzImplementsInterface(clazz, Event.class)) {
            throw new FlexinaleIllegalArgumentException("need to use Event class %s to retrieve class name"
                    .formatted(clazzName));
        }

        return getEventClazzVersion(clazz);
    }

    public static <E extends Event> Versionable.Version getEventClazzVersion(final Class<E> clazz) {
        try {
            Constructor<E> constructor = clazz.getDeclaredConstructor();
            constructor.setAccessible(true);
            Event e = constructor.newInstance();
            return e.version();
        }
        catch (Exception ex) {
            throw new FlexinaleIllegalArgumentException("error when instantiating Event class %s or retrieving its version"
                    .formatted(getEventClazzName(clazz)), ex);
        }
    }
}
