package be.iminds.ilabt.jfed.lowlevel.api.test;

import be.iminds.ilabt.jfed.testing.base.ApiTest;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;

/**
 * TestClassList
 */
public class TestClassList {
    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(TestClassList.class);

    private static final TestClassList ourInstance = new TestClassList();

    private TestClassList() {
    }

    public static TestClassList getInstance() {
        return ourInstance;
    }

//    private static List<String> allTestClasses() {
//        return getInstance().allTestClasses();
//    }

    public List<String> allTestClasses() {
        ArrayList<String> res = new ArrayList<>();
        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.ConnectivityTestSliceAuthority");
        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestAnyGetVersion");
        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestAnyServiceGetVersion");
        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.ConnectivityTestAggregateManager3");
        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.ConnectivityTestAggregateManager2");

        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestSliceAuthority");
        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestAggregateManager2");
        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestAggregateManager3");

        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestNodeLogin");
        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestMultiNodeLogin");

        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestAggregateManager2ListResources");
        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestAggregateManager3ListResources");
        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestAggregateManager2NitosHack");

        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.StitchingPingTest");

//        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestDelegationAggregateManager2");

        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestFederationMemberAuthority1");
        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestFederationSliceAuthority1");
        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestFederationRegistry1");

        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestFederationMemberAuthority2");
        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestFederationSliceAuthority2");
        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestFederationRegistry2");

        res.add("be.iminds.ilabt.jfed.lowlevel.api.test.TestBestEffortAMv3");

        //res.add("be.iminds.ilabt.jfed.highlevel.stitcher.automated_test.ParallelStitchingPingTest");

        for (Iterator<String> it = res.iterator(); it.hasNext(); ) {
            String className = it.next();
            try {
                Class<?> c = Class.forName(className);
                if (!ApiTest.class.isAssignableFrom(c)) {
                    LOG.error("Error in TestClassList.allTestClasses(): class \"" + className + "\" does not extend ApiTest");
                    it.remove();
                }
            } catch (ClassNotFoundException e) {
                LOG.error("Error in TestClassList.allTestClasses(): class \"" + className + "\" not found", e);
                it.remove();
            }
        }

        return res;
    }

    public Collection<String> getGroups(Class<? extends ApiTest> clazz) {
        Set<String> res = new HashSet<>();

        //get list of annotated methods
        List<Method> methods = Arrays.asList(clazz.getMethods());
        for (Method m : methods) {
            Annotation[] annotations = m.getDeclaredAnnotations();
            for (Annotation annotation : annotations) {
                if (annotation instanceof ApiTest.Test) {
                    ApiTest.Test testAn = (ApiTest.Test) annotation;
                    Collections.addAll(res, testAn.groups());
                }
            }
        }

        return res;
    }

    public Collection<String> getGroups(String className) {
        try {
            Class<?> c = Class.forName(className);
            if (!ApiTest.class.isAssignableFrom(c)) {
                throw new RuntimeException("Class \"" + className + "\" is not an ApiTest class");
            }
            Class<? extends ApiTest> cc = (Class<? extends ApiTest>) c;
            return getGroups(cc);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("Class \"" + className + "\" not found", e);
        }
    }
}
