package com.arrebol.taxiservicios.controller.system;

import com.arrebol.taxiservicios.controller.connection.ConnectionManager;
import com.arrebol.taxiservicios.controller.util.HibernateUtil;
import com.arrebol.taxiservicios.model.core.Permission;
import com.arrebol.taxiservicios.model.core.Person;
import com.arrebol.taxiservicios.model.core.User;
import com.arrebol.taxiservicios.model.core.UserHasPermission;
import java.io.Serializable;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Root;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

/**
 *
 * @author Carlos Janitzio Zavala Lopez
 */
public class PermissionController extends ConnectionManager implements Serializable {

    /**
     * Get all user in Taxi Servicios App.
     *
     * @return
     */
    public List<User> getAllActiveUserAndNotRoot() {
        logger.info("Start getAllActiveUserAndNotRoot");

        Transaction transaction = null;
        List<User> users = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<User> criteria = builder.createQuery(User.class);
            Root<User> root = criteria.from(User.class);

            Path<String> idPath = root.get("id");
            Path<String> userNamePath = root.get("userName");

            criteria.select(builder.construct(User.class, idPath, userNamePath));

            criteria.where(
                    builder.and(
                            builder.equal(root.get("active"), true),
                            builder.equal(root.get("root"), false)
                    )
            );

            users = session.createQuery(criteria).getResultList();

            transaction.commit();
            logger.info("Users successfully loaded");
            logger.info(users);
        } catch (HibernateException e) {
            logger.error("Get all users can not be readed ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method getAllActiveUserAndNotRoot()", e);
            rollback(transaction);
        }
        return users;
    }

    /**
     * Load user details by ID.
     *
     * @param id Identify number.
     * @return User by Id.
     */
    public User loadUserById(String id) {
        logger.info("Start loadUserById");

        Transaction transaction = null;
        User user = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            user = session.load(User.class, id);

            transaction.commit();
            logger.info("User successfully loaded");
            logger.info(user);
        } catch (HibernateException e) {
            logger.error("User can not be readed ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method loadUserById()", e);
            rollback(transaction);
        }
        return user;
    }

    /**
     *
     * @return
     */
    public List<Permission> getAllPermissionOrderByMenuLevel() {
        logger.info("getAllPermissionOrderByMenuLevel");

        List<Permission> permissions = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<Permission> query = builder.createQuery(Permission.class);

            Root<Permission> root = query.from(Permission.class);

            Path<String> id = root.get("id");
            Path<String> name = root.get("name");
            Path<String> description = root.get("description");
            Path<Integer> level = root.get("level");

            query.select(
                    builder.construct(
                            Permission.class, id, name, description, level
                    )
            );
            query.orderBy(builder.asc(root.get("level")));

            permissions = session.createQuery(query).getResultList();

            transaction.commit();
            logger.info("Total of permissions loaded " + permissions.size());
        } catch (HibernateException e) {
            logger.error("Permissions cannot be loaded ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method getAllServiceOrderActive() ", e);
            rollback(transaction);
        }
        return permissions;
    }

    /**
     *
     * @param like
     * @return
     */
    public List<String> searchUsers(String like) {
        logger.info("searchUsers");

        List<String> resultList = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<String> query = builder.createQuery(String.class);
            Root<User> root = query.from(User.class);

            query.select(root.get("userName"));
            query.where(
                    builder.like(root.get("userName"), "%" + like + "%"),
                    builder.and(builder.equal(root.get("active"), true))
            );

            resultList = session.createQuery(query).getResultList();

            transaction.commit();
            logger.info("Coincidences " + resultList);
        } catch (HibernateException e) {
            logger.error("Users cannot be loaded " + like, e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method searchUsers(" + like + ") ", e);
            rollback(transaction);
        }
        return resultList;
    }

    /**
     * Get user details by user name, search for first, second, last and middle
     * names.
     *
     * @param userName
     * @return user details.
     */
    public User findUserByUserName(String userName) {
        logger.info("findUserByUserName");

        User user = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<User> query = builder.createQuery(User.class);
            Root<User> root = query.from(User.class);

            Path<Person> person = root.get("person");
            Path<String> id = root.get("id");

            query.select(builder.construct(User.class, person, id));
            query.where(builder.equal(root.get("userName"), userName));

            user = session.createQuery(query).uniqueResult();

            transaction.commit();
            logger.info("User " + user);
        } catch (HibernateException e) {
            logger.error("User cannot be loaded " + userName, e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findUserByUserName(" + userName + ") ", e);
            rollback(transaction);
        }
        return user;
    }

    /**
     *
     * @param userId
     * @return
     */
    public List<UserHasPermission> findAllPermissionFromUser(String userId) {
        logger.info("findUserByUserName");

        List<UserHasPermission> permissions = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<UserHasPermission> query = builder.createQuery(UserHasPermission.class);
            Root<UserHasPermission> root = query.from(UserHasPermission.class);

            Path<Permission> permission = root.get("permission");

            query.select(builder.construct(UserHasPermission.class, permission));
            query.where(builder.equal(root.get("user"), new User(userId, "")));
            query.orderBy(builder.asc(root.get("permission")));

            permissions = session.createQuery(query).getResultList();

            transaction.commit();
            logger.info("Permissions loaded " + permissions);
        } catch (HibernateException e) {
            logger.error("Permission cannot be loaded " + userId, e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findAllPermissionFromUser(" + userId + ") ", e);
            rollback(transaction);
        }
        return permissions;
    }

    /**
     *
     * @return
     */
    public List<Permission> getAllPermissions() {
        logger.info("getAllPermissiona");

        List<Permission> permissions = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<Permission> query = builder.createQuery(Permission.class);
            Root<Permission> root = query.from(Permission.class);

            Path<String> id = root.get("id");
            Path<String> name = root.get("name");
            Path<String> description = root.get("description");
            Path<Integer> level = root.get("level");

            query.select(builder.construct(Permission.class, id, name, description, level));
            query.orderBy(builder.asc(root.get("level")));

            permissions = session.createQuery(query).getResultList();

            transaction.commit();
            logger.info("Permissions loaded " + permissions);
        } catch (HibernateException e) {
            logger.error("Permission cannot be loaded ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method getAllPermissiona() ", e);
            rollback(transaction);
        }
        return permissions;
    }

    private static final long serialVersionUID = -1263145002515224204L;

    final Logger logger = LogManager.getLogger(PermissionController.class);

}
