package util;


import models.Searchable;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import play.Logger;
import play.db.jpa.GenericModel;
import play.db.jpa.Model;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by dom on 30/3/2019.
 */
public class Search {

    public List<Class> classList = new ArrayList<Class>();

    public Map<Class, List<Field>> classFieldMap = new HashMap<Class, List<Field>>();

    public Search() {
        try {
            classList.add(Class.forName("models.contacts.Contact"));
            classList.add(Class.forName("models.contacts.Customer"));
            classList.add(Class.forName("models.contacts.Person"));
            classList.add(Class.forName("models.AppUser"));
            classList.add(Class.forName("models.Document"));
            classList.add(Class.forName("models.DBFile"));
            classList.add(Class.forName("models.Task"));
            classList.add(Class.forName("models.projects.Project"));
            classList.add(Class.forName("models.projects.Lead"));
            classList.add(Class.forName("models.projects.Deliverable"));
        } catch (ClassNotFoundException e) {
            Logger.error("Class not found in Search Initialization" + e.getMessage());

        }

        for (Class c : classList) {
            if (!play.db.jpa.Model.class.isAssignableFrom(c)) {
                throw new ClassCastException(c.getCanonicalName() + " is not a model");
            }
            Field[] declaredFields = c.getDeclaredFields();
            for (Field field : declaredFields) {
                if (field.isAnnotationPresent(Searchable.class)) {
                    Logger.info("inside searchable field is : " +field);
                    if (classFieldMap.get(c) == null) {
                        classFieldMap.put(c, new ArrayList<Field>());
                    }
                    classFieldMap.get(c).add(field);
                }
            }
        }

    }

    public static void getClasses() {
    }

    public static boolean isSimilar(Model a, Model b) {
        return a.id.equals(b.id);
    }

    public static boolean hasSimilarInList(Model a, Set<Model> bList) {
        for (Model b : bList) {
            if (isSimilar(a, b)) {
                return true;
            }
        }
        return false;
    }

    public Set<Model> doSearch(String query) throws NoSuchMethodException {
        Set<Model> resultSet = new HashSet<Model>();
        Logger.info("to query arxi " + query);

        for (Class c : classFieldMap.keySet()) {
            Method find = c.getMethod("find", String.class, Object[].class);
            String[] querystring = new String[1];
            querystring[0] = query;

            for (Field field : classFieldMap.get(c)) {
                if (resultSet.size() > 90) return resultSet;   //bring only the top 10 results
                try {

                    Logger.info("which field -- "+field.getName());

                    String name = field.getName();
                    String jpqlString = "by" + name.substring(0, 1).toUpperCase() + name.substring(1) + "Ilike";
                    Object[] objs = {"%" + query + "%"};
                    Object result = find.invoke(null, jpqlString, objs);
                    List<Model> objectList = ((GenericModel.JPAQuery) result).fetch();
                    resultSet.addAll(objectList);

                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }

            }

//            boolean isDate = EventUtil.checkIfDate(query);
//            //Logger.info("isDate " + isDate);
//            if (isDate) {
//                for (Class cl : classFieldMap.keySet()) {
//                    find = cl.getMethod("find", String.class, Object[].class);
//                    Integer[] queryDate = new Integer[3];
//                    queryDate[0] = DateTimeFormat.forPattern("dd/MM/yyyy").parseDateTime(query).getDayOfMonth();
//                    queryDate[1] = DateTimeFormat.forPattern("dd/MM/yyyy").parseDateTime(query).getMonthOfYear();
//                    queryDate[2] = DateTimeFormat.forPattern("dd/MM/yyyy").parseDateTime(query).getYear();
//                    for (Field field : classFieldMap.get(cl)) {
//                        if (resultSet.size() > 90) return resultSet;   //bring only the top 10 results
//                        try {
//                            String name = field.getName();
//                            if (field.getType().equals(DateTime.class)) {
//                                String jpqlString = "DAY(" + name + ")=? AND MONTH(" + name + ")=? AND YEAR(" + name + ")=?";
//                                Object result = find.invoke(null, jpqlString, queryDate);
//                                List<Model> objectList = ((GenericModel.JPAQuery) result).fetch();
//                                resultSet.addAll(objectList);
//                            }
//                        } catch (IllegalAccessException e) {
//                            e.printStackTrace();
//                        } catch (InvocationTargetException e) {
//                            e.printStackTrace();
//                        }
//
//                    }
//                }
//
//            }

        }
        return resultSet;
    }
}

