/*
 * Arrebol Consultancy copyright.
 * 
 * This code belongs to Arrebol Consultancy
 * its use, redistribution or modification are prohibited 
 * without written authorization from Arrebol Consultancy.
 */
package com.arrebol.taxiservicios.controller.notification;

import com.arrebol.taxiservicios.controller.connection.ConnectionManager;
import com.arrebol.taxiservicios.controller.queries.ServiceOrderNotificationDeliveryToNQ;
import com.arrebol.taxiservicios.controller.queries.ServiceOrderNotificationNQ;
import com.arrebol.taxiservicios.controller.queries.StopNotificationNQ;
import com.arrebol.taxiservicios.controller.queries.UserNQ;
import com.arrebol.taxiservicios.controller.util.HibernateUtil;
import com.arrebol.taxiservicios.model.core.User;
import com.arrebol.taxiservicios.model.enums.DeliveryStatusType;
import com.arrebol.taxiservicios.model.notification.StopNotification;
import com.arrebol.taxiservicios.model.stocktaking.ServiceOrderNotification;
import com.arrebol.taxiservicios.model.stocktaking.ServiceOrderNotificationDeliveryTo;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.enterprise.context.SessionScoped;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaDelete;
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 <janitzio.zavala@arrebol.com.mx>
 */
@SessionScoped
public class NotificationServiceImpl extends ConnectionManager implements NotificationService, Serializable {

    /**
     *
     * @param userId
     * @return
     */
    @Override
    public int countNotificationByUserId(String userId) {
        logger.debug("countNotificationByUserId");
        int total = 0;

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

            Long count = (Long) session.createNamedQuery(ServiceOrderNotificationDeliveryToNQ.QUERY_COUNT_NOTIFICATION_BY_USER_ID)
                    .setParameter(ServiceOrderNotificationDeliveryToNQ.FIELD_USER, new User(userId, ""))
                    .uniqueResult();

            total = count.intValue();

            transaction.commit();
            logger.debug("countNotificationByUserId: " + total);
        } catch (HibernateException e) {
            logger.error("Count notification hibernate exception ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method countNotificationByUserId() ", e);
            rollback(transaction);
        }
        return total;
    }

    /**
     *
     * @param userId
     * @param statusType
     * @return
     */
    @Override
    public List<ServiceOrderNotification> findNotificationDetailsByUserId(String userId, DeliveryStatusType statusType) {
        logger.debug("findNotificationDetailsByUserId");

        List<ServiceOrderNotification> notifications = new ArrayList<>();
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            notifications = session.createNamedQuery(ServiceOrderNotificationNQ.QUERY_FIND_NOTIFICATION_DETAILS_BY_USER_ID_AND_DELIVERY_STATUS)
                    .setParameter(ServiceOrderNotificationDeliveryToNQ.FIELD_USER, new User(userId, ""))
                    .setParameter(ServiceOrderNotificationDeliveryToNQ.FIELD_STATUS_TYPE, statusType)
                    .getResultList();

            transaction.commit();
            logger.debug("Total of notifications details  by user id: " + notifications.size());
        } catch (HibernateException e) {
            logger.error("findNotificationDetailsByUserId hibernate ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findNotificationDetailsByUserId() ", e);
            rollback(transaction);
        }
        return notifications;
    }

    /**
     *
     * @param userId
     * @return
     */
    @Override
    public boolean isActiveNotificationByUser(String userId) {
        logger.debug("isActiveNotificationByUser");

        boolean activeNotification = true;
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            StopNotification notification = session
                    .createNamedQuery(StopNotificationNQ.QUERY_IS_ACTIVE_NOTIFICATION_BY_USER, StopNotification.class)
                    .setParameter(StopNotificationNQ.FIELD_USER, new User(userId, ""))
                    .uniqueResult();

            if (null != notification) {
                activeNotification = false;
            }

            transaction.commit();
            logger.debug("User has " + (activeNotification ? "activated" : "stoped") + " his notifications");
        } catch (HibernateException e) {
            logger.error("isActiveNotificationByUser hibernate ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method isActiveNotificationByUser() ", e);
            rollback(transaction);
        }

        return activeNotification;
    }

    /**
     *
     * @param userId user to enebled/disabled notifications
     * @param notification If notifications is null notifications will set to
     * enebled delete a current record, otherwise set as disabled adding the
     * user into stop notification table.
     */
    @Override
    public void stopNotifiationByUser(String userId, StopNotification notification) {
        logger.debug("stopNotificationByUser");
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            if (null != notification) {
                session.save(notification);
            } else {
                CriteriaBuilder builder = session.getCriteriaBuilder();
                CriteriaDelete<StopNotification> delete = builder.createCriteriaDelete(StopNotification.class);
                Root<StopNotification> root = delete.from(StopNotification.class);

                delete.where(builder.equal(root.get("user"), new User(userId, "")));

                session.createQuery(delete).executeUpdate();
            }

            transaction.commit();
            logger.debug("stopNotificationByUser saved");
        } catch (HibernateException e) {
            logger.error("stopNotificationByUser hibernate ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method stopNotificationByUser() ", e);
            rollback(transaction);
        }
    }

    /**
     *
     * @param isOnStopNotification True get users innotification table, false
     * get all users that are not in stop notification table.
     * @return
     */
    @Override
    public List<User> findNotificationUsers(boolean isOnStopNotification) {
        logger.debug("findNotificationUsers");
        List<User> users = new ArrayList<>();

        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            users = session.createNamedQuery(
                    isOnStopNotification
                            ? UserNQ.QUERY_FIND_NOTIFICATION_USERS
                            : UserNQ.QUERY_FIND_USERS_WITHOUT_NOTIFICATION,
                    User.class).getResultList();

            transaction.commit();
            logger.debug("users found findNotificationUsers");
        } catch (HibernateException e) {
            logger.error("stopNotificationByUser hibernate ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method stopNotificationByUser() ", e);
            rollback(transaction);
        }

        return users;
    }

    /**
     *
     * @param newNotifications
     * @return
     */
    @Override
    public boolean updateStopNotificationData(List<StopNotification> newNotifications) {
        logger.debug("updateStopNotificationData");

        boolean success = false;
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            List<StopNotification> toDeleteLst = session.createNamedQuery(StopNotificationNQ.QUERY_GET_ALL_STOP_NOTIFICATION, StopNotification.class).getResultList();

            toDeleteLst.forEach((toDelete) -> {
                session.delete(toDelete);
            });

            session.flush();
            session.clear();

            newNotifications.forEach((notification) -> {
                session.save(notification);
            });

            transaction.commit();
            logger.debug("Save new stop notification data");

            success = true;
        } catch (HibernateException e) {
            logger.error("updateStopNotificationData hibernate ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updateStopNotificationData() ", e);
            rollback(transaction);
        }
        return success;
    }

    /**
     *
     * @param orderNotificationId
     * @param userId
     * @return True if notification was deleted otherwise false.
     */
    @Override
    public boolean deleteNotificationRecipient(String orderNotificationId, String userId) {
        logger.debug("deleteNotificationRecipient");
        boolean success = false;
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            ServiceOrderNotificationDeliveryTo deliveryTo
                    = session.createNamedQuery(ServiceOrderNotificationDeliveryToNQ.QUERY_FIND_DELIVERY_NOTIFICATION, ServiceOrderNotificationDeliveryTo.class)
                            .setParameter(ServiceOrderNotificationDeliveryToNQ.FIELD_USER, new User(userId, ""))
                            .setParameter(ServiceOrderNotificationDeliveryToNQ.FIELD_SERVICE_ORDER_NOTIFICATION, new ServiceOrderNotification(orderNotificationId))
                            .uniqueResult();

            if (null != deliveryTo) {
                session.delete(deliveryTo);
            }

            transaction.commit();
            logger.debug("Was delete");
        } catch (HibernateException e) {
            logger.error("deleteNotificationRecipient hibernate ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method deleteNotificationRecipient() ", e);
            rollback(transaction);
        }
        return success;
    }

    @Override
    public boolean cleanAllNotificationsByUser(String userId) {
        logger.debug("cleanAllNotificationsByUser");
        boolean success = false;
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            List<ServiceOrderNotificationDeliveryTo> deliveryLst
                    = session.createNamedQuery(ServiceOrderNotificationDeliveryToNQ.QUERY_FIND_DELIVERY_NOTIFICATION_BY_USER, ServiceOrderNotificationDeliveryTo.class)
                            .setParameter(ServiceOrderNotificationDeliveryToNQ.FIELD_USER, new User(userId, ""))
                            .getResultList();

            deliveryLst.forEach((delivery) -> {
                session.delete(delivery);
            });

            transaction.commit();
            logger.debug("Was delete");
        } catch (HibernateException e) {
            logger.error("cleanAllNotificationsByUser hibernate ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method cleanAllNotificationsByUser() ", e);
            rollback(transaction);
        }
        return success;
    }

    private static final long serialVersionUID = 9155426554514505718L;

    private final Logger logger = LogManager.getLogger(getClass());

}
