package com.viettel.campaign.service.impl;

import com.github.tennaito.rsql.jpa.JpaCriteriaCountQueryVisitor;
import com.github.tennaito.rsql.jpa.JpaCriteriaQueryVisitor;
import com.viettel.campaign.config.DataSourceQualify;
import com.viettel.campaign.mapper.CustomerListMapper;
import com.viettel.campaign.mapper.CustomerMapper;
import com.viettel.campaign.model.ccms_full.Customer;
import com.viettel.campaign.model.ccms_full.CustomerContact;
import com.viettel.campaign.model.ccms_full.CustomerList;
import com.viettel.campaign.repository.ccms_full.*;
import com.viettel.campaign.service.CustomerService;
import com.viettel.campaign.utils.*;
import com.viettel.campaign.web.dto.*;
import com.viettel.campaign.web.dto.request_dto.CustomerDetailRequestDTO;
import com.viettel.campaign.web.dto.request_dto.CustomerRequestDTO;
import com.viettel.campaign.web.dto.request_dto.SearchCustomerRequestDTO;
import com.viettel.econtact.filter.UserSession;
import cz.jirutka.rsql.parser.RSQLParser;
import cz.jirutka.rsql.parser.ast.Node;
import cz.jirutka.rsql.parser.ast.RSQLVisitor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.eclipse.jetty.client.HttpRequest;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.transform.Transformers;
import org.hibernate.type.DateType;
import org.hibernate.type.LongType;
import org.hibernate.type.ShortType;
import org.hibernate.type.StringType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.*;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ResourceUtils;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;
import javax.servlet.http.HttpServletRequest;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.*;

@Service
public class CustomerServiceImpl implements CustomerService {

    @Autowired
    @PersistenceContext( unitName= DataSourceQualify.JPA_UNIT_NAME_CCMS_FULL)
    EntityManager entityManager;

    @Autowired
    CustomerRepository customerRepository;

    @Autowired
    CustomerListRepository customerListRepository;

    @Autowired
    CustomerContactRepository customerContactRepository;

    @Autowired
    CampaignCustomerListRepository campaignCustomerListRepository;

    @Autowired
    CampaignCustomerRepository campaignCustomerRepository;

    @Autowired
    CustomerListMappingRepository customerListMappingRepository;

    @Autowired
    @Qualifier(DataSourceQualify.NAMED_JDBC_PARAMETER_TEMPLATE_CCMS_FULL)
    NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    @Autowired
    VSAUsersRepository vsaUsersRepository;

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO getAllCustomer(int page, int pageSize, String sort, long customerListId, long companySiteId) {
        ResultDTO resultDTO = new ResultDTO();
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

        Session session = sessionFactory.openSession();
        session.beginTransaction();

        if (DataUtil.isNullOrZero(companySiteId)) {
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
            return resultDTO;
        }

        try {
//            StringBuilder sqlStrBuilder = new StringBuilder();
//            sqlStrBuilder.append(SQLBuilder.getSqlQueryById(SQLBuilder.SQL_MODULE_CAMPAIGN_MNG, "campaign-customer-detail-by-params"));

            //sqlStrBuilder.append(" ORDER BY b.NAME ASC");
            StringBuilder sb = new StringBuilder();

            sb.append("select");
            sb.append("    a.CUSTOMER_LIST_MAPPING_ID customerListMappingId,");
            sb.append("    a.COMPANY_SITE_ID companySiteId,");
            sb.append("    a.CUSTOMER_LIST_ID customerListId,");
            sb.append("    a.CUSTOMER_ID customerId,");
            sb.append("    b.NAME name,");
            sb.append("    b.DESCRIPTION description,");
            sb.append("    b.COMPANY_NAME companyName,");
            sb.append("    b.CUSTOMER_TYPE customerType,");
            sb.append("    b.CURRENT_ADDRESS currentAddress,");
            sb.append("    b.CALL_ALLOWED callAllowed,");
            sb.append("    b.EMAIL_ALLOWED emailAllowed,");
            sb.append("    b.SMS_ALLOWED smsAllowed,");
            sb.append("    b.IPCC_STATUS ipccStatus,");
            sb.append("    c.MOBILE mobileNumber,");
            sb.append("    d.EMAIL email");
            sb.append(" from CUSTOMER_LIST_MAPPING a");
            sb.append("         join CUSTOMER b on a.CUSTOMER_ID = b.CUSTOMER_ID");
            sb.append("         left join (SELECT CUSTOMER_ID, LISTAGG(CONTACT, ', ') WITHIN GROUP (ORDER BY ");
            sb.append(" NULL) AS MOBILE");
            sb.append("               FROM CUSTOMER_CONTACT WHERE CONTACT_TYPE = 5 GROUP BY ");
            sb.append(" CUSTOMER_ID) c on b.CUSTOMER_ID = c.CUSTOMER_ID");
            sb.append("         left join (SELECT CUSTOMER_ID, LISTAGG(CONTACT, ', ') WITHIN GROUP (ORDER BY ");
            sb.append(" NULL) AS EMAIL");
            sb.append("               FROM CUSTOMER_CONTACT WHERE CONTACT_TYPE = 2 GROUP BY ");
            sb.append(" CUSTOMER_ID) d on b.CUSTOMER_ID = d.CUSTOMER_ID ");
            sb.append(" where 1 = 1");
            sb.append("   and a.COMPANY_SITE_ID = :p_company_site_id");
            sb.append("   and a.CUSTOMER_LIST_ID = :p_customer_list_id");
            sb.append(" ORDER BY b.NAME ASC");

            SQLQuery query = session.createSQLQuery(sb.toString());

            query.setParameter("p_company_site_id", companySiteId);
            query.setParameter("p_customer_list_id", customerListId);

            query.addScalar("customerListMappingId", new LongType());
            query.addScalar("companySiteId", new LongType());
            query.addScalar("customerListId", new LongType());
            query.addScalar("customerId", new LongType());
            query.addScalar("name", new StringType());
            query.addScalar("description", new StringType());
            query.addScalar("companyName", new StringType());
            query.addScalar("customerType", new StringType());
            query.addScalar("currentAddress", new StringType());
            query.addScalar("callAllowed", new ShortType());
            query.addScalar("emailAllowed", new ShortType());
            query.addScalar("smsAllowed", new ShortType());
            query.addScalar("ipccStatus", new StringType());
            query.addScalar("mobileNumber", new StringType());
            query.addScalar("email", new StringType());

            query.setResultTransformer(Transformers.aliasToBean(CustomerCustomDTO.class));
            int count = 0;
            List<CustomerCustomDTO> dtoList = query.list();
            if (dtoList.size() > 0) {
                count = query.list().size();
            }

            Pageable pageable = PageRequest.of(page, pageSize, Sort.by(Sort.Order.desc(sort)));
            if (pageable != null) {
                query.setFirstResult(pageable.getPageNumber() * pageable.getPageSize());
                query.setMaxResults(pageable.getPageSize());
            }

            List<CustomerCustomDTO> data = query.list();
            Page<CustomerCustomDTO> dataPage = new PageImpl<>(data, pageable, count);
            resultDTO.setData(dataPage);
            resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
            resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
        } catch (Exception e) {
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
        } finally {
            session.close();
        }

        return resultDTO;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO getCustomerId(Long customerId) {
        ResultDTO resultDTO = new ResultDTO();

        List<Customer> customer = customerRepository.findByCustomerId(customerId);

        if (customer != null) {
            resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
            resultDTO.setDescription("customer data");
            resultDTO.setListData(customer);
        } else {
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription("customer data null");
        }

        return resultDTO;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO searchAllCustomer(int page, int pageSize, String sort, long customerListId, long companySiteId, String name, String mobileNumber, String email) {
        ResultDTO resultDTO = new ResultDTO();
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

        Session session = sessionFactory.openSession();
        session.beginTransaction();

        if (DataUtil.isNullOrZero(companySiteId)) {
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
            return resultDTO;
        }

        try {
//            StringBuilder sqlStrBuilder = new StringBuilder();
//            sqlStrBuilder.append(SQLBuilder.getSqlQueryById(SQLBuilder.SQL_MODULE_CAMPAIGN_MNG, "campaign-customer-detail-by-params"));

            StringBuilder sb = new StringBuilder();

            sb.append("select");
            sb.append("    a.CUSTOMER_LIST_MAPPING_ID customerListMappingId,");
            sb.append("    a.COMPANY_SITE_ID companySiteId,");
            sb.append("    a.CUSTOMER_LIST_ID customerListId,");
            sb.append("    a.CUSTOMER_ID customerId,");
            sb.append("    b.NAME name,");
            sb.append("    b.DESCRIPTION description,");
            sb.append("    b.COMPANY_NAME companyName,");
            sb.append("    b.CUSTOMER_TYPE customerType,");
            sb.append("    b.CURRENT_ADDRESS currentAddress,");
            sb.append("    b.CALL_ALLOWED callAllowed,");
            sb.append("    b.EMAIL_ALLOWED emailAllowed,");
            sb.append("    b.SMS_ALLOWED smsAllowed,");
            sb.append("    b.IPCC_STATUS ipccStatus,");
            sb.append("    c.MOBILE mobileNumber,");
            sb.append("    d.EMAIL email");
            sb.append(" from CUSTOMER_LIST_MAPPING a");
            sb.append("         join CUSTOMER b on a.CUSTOMER_ID = b.CUSTOMER_ID");
            sb.append("         left join (SELECT CUSTOMER_ID, LISTAGG(CONTACT, ', ') WITHIN GROUP (ORDER BY NULL) AS MOBILE");
            sb.append("               FROM CUSTOMER_CONTACT WHERE CONTACT_TYPE = 5 GROUP BY CUSTOMER_ID) c on b.CUSTOMER_ID = c.CUSTOMER_ID");
            sb.append("         left join (SELECT CUSTOMER_ID, LISTAGG(CONTACT, ', ') WITHIN GROUP (ORDER BY NULL) AS EMAIL");
            sb.append("               FROM CUSTOMER_CONTACT WHERE CONTACT_TYPE = 2 GROUP BY CUSTOMER_ID) d on b.CUSTOMER_ID = d.CUSTOMER_ID");
            sb.append(" where 1 = 1");
            sb.append("   and a.COMPANY_SITE_ID = :p_company_site_id");
            sb.append("   and a.CUSTOMER_LIST_ID = :p_customer_list_id");

            if (!DataUtil.isNullOrEmpty(name)) {
                sb.append(" AND UPPER(b.NAME) LIKE UPPER(:p_name)");
            }
            if (!DataUtil.isNullOrEmpty(mobileNumber)) {
                sb.append(" AND UPPER(c.MOBILE) LIKE UPPER(:p_mobile_number)");
            }
            if (!DataUtil.isNullOrEmpty(email)) {
                sb.append(" AND UPPER(d.EMAIL) LIKE UPPER(:p_email)");
            }
            sb.append(" ORDER BY name DESC");

            SQLQuery query = session.createSQLQuery(sb.toString());

            query.setParameter("p_company_site_id", companySiteId);
            query.setParameter("p_customer_list_id", customerListId);

            if (!DataUtil.isNullOrEmpty(name)) {
                query.setParameter("p_name", "%" +
                        name.replace("\\", "\\\\")
                                .replaceAll("%", "\\%")
                                .replaceAll("_", "\\_")
                        + "%");
            }

            if (!DataUtil.isNullOrEmpty(mobileNumber)) {
                query.setParameter("p_mobile_number", "%" +
                        mobileNumber.replace("\\", "\\\\")
                                .replaceAll("%", "\\%")
                                .replaceAll("_", "\\_")
                        + "%");
            }

            if (!DataUtil.isNullOrEmpty(email)) {
                query.setParameter("p_email", "%" +
                        email.replace("\\", "\\\\")
                                .replaceAll("%", "\\%")
                                .replaceAll("_", "\\_")
                        + "%");
            }

            query.addScalar("customerListMappingId", new LongType());
            query.addScalar("companySiteId", new LongType());
            query.addScalar("customerListId", new LongType());
            query.addScalar("customerId", new LongType());
            query.addScalar("name", new StringType());
            query.addScalar("description", new StringType());
            query.addScalar("companyName", new StringType());
            query.addScalar("customerType", new StringType());
            query.addScalar("currentAddress", new StringType());
            query.addScalar("mobileNumber", new StringType());
            query.addScalar("email", new StringType());

            query.setResultTransformer(Transformers.aliasToBean(CustomerCustomDTO.class));
            int count = 0;
            List<CustomerCustomDTO> dtoList = query.list();
            if (dtoList.size() > 0) {
                count = query.list().size();
            }

            Pageable pageable = PageRequest.of(page, pageSize, Sort.by(Sort.Order.desc(sort)));
            if (pageable != null) {
                query.setFirstResult(pageable.getPageNumber() * pageable.getPageSize());
                query.setMaxResults(pageable.getPageSize());
            }

            List<CustomerCustomDTO> data = query.list();
            Page<CustomerCustomDTO> dataPage = new PageImpl<>(data, pageable, count);
            resultDTO.setData(dataPage);
            resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
            resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
        } catch (Exception e) {
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
        } finally {
            session.close();
        }

        return resultDTO;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO createCustomer(CustomerDTO customerDTO) {
        ResultDTO resultDTO = new ResultDTO();
        CustomerMapper customerMapper = new CustomerMapper();
        Customer customer = new Customer();

        try {
            if (customerDTO != null) {
                //check trung mobile number
                Long cusExist = customerRepository.findByMobileNumberAndSiteId(customerDTO.getMobileNumber(), customerDTO.getSiteId());
                if (cusExist > 0) {
                    resultDTO.setErrorCode("-7");
                    resultDTO.setDescription("Mobile number is existed");
                    return resultDTO;
                }

                // insert
                customer = customerMapper.toPersistenceBean(customerDTO);
                customer.setCreateDate(new Date());
                customer = customerRepository.save(customer);

                resultDTO.setErrorCode(customer.getCustomerId() + "");
                resultDTO.setDescription("customer created");
            } else {
                resultDTO.setErrorCode("-2");
                resultDTO.setDescription("customerDTO null");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return resultDTO;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO deleteCustomer(CustomerRequestDTO customerRequestDTO) {
        ResultDTO resultDTO = new ResultDTO();
        try {
            if (customerRequestDTO != null) {
                // delete
//                customerRepository.deleteById(customerDTO.getCustomerId());
                customerListMappingRepository.deleteMappingByCustomerId(customerRequestDTO.getCustomerId(), customerRequestDTO.getCustomerListId(), customerRequestDTO.getCompanySiteId());

                resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
                resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
            } else {
                resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
                resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return resultDTO;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO deleteIds(CustomerRequestDTO customerRequestDTO) {
        ResultDTO resultDTO = new ResultDTO();
        try {
            if (customerRequestDTO != null) {
//                customerRepository.deleteIds(ids);
                customerListMappingRepository.deleteMappingByCustomerIds(customerRequestDTO.getIds(), customerRequestDTO.getCustomerListId(), customerRequestDTO.getCompanySiteId());
                resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
                resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
            } else {
                resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
                resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultDTO;
    }

    @Override
    public ResultDTO getCustomerDetailById(Long companySiteId, Long customerListId, Long customerId) {
        ResultDTO resultDTO = new ResultDTO();
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

        Session session = sessionFactory.openSession();
        session.beginTransaction();

        if (DataUtil.isNullOrZero(companySiteId)) {
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
            return resultDTO;
        }

        try {
//            StringBuilder sqlStrBuilder = new StringBuilder();
//            sqlStrBuilder.append(SQLBuilder.getSqlQueryById(SQLBuilder.SQL_MODULE_CAMPAIGN_MNG, "get-customer-detail-by-id"));
            StringBuilder sb = new StringBuilder();

            sb.append("select");
            sb.append("    a.COMPANY_SITE_ID companySiteId,");
            sb.append("    a.CUSTOMER_LIST_ID customerListId,");
            sb.append("    a.CUSTOMER_ID customerId,");
            sb.append("    e.TITLE title,");
            sb.append("    f.TYPE type,");
            sb.append("    h.VALUE_COMBOBOX valueCombobox,");
            sb.append("    e.VALUE_CHECKBOX valueCheckbox,");
            sb.append("    e.VALUE_DATE valueDate,");
            sb.append("    e.VALUE_NUMBER valueNumber,");
            sb.append("    e.VALUE_TEXT valueText");
            sb.append(" from CUSTOMER_LIST_MAPPING a");
            sb.append("         left join CUSTOMIZE_FIELD_OBJECT e on a.CUSTOMER_ID = e.OBJECT_ID");
            sb.append("         left join CUSTOMIZE_FIELDS f on e.CUSTOMIZE_FIELDS_ID = f.CUSTOMIZE_FIELD_ID");
            sb.append("         left join (SELECT FIELD_OPTION_VALUE_ID, NAME AS VALUE_COMBOBOX");
            sb.append("                    FROM CUSTOMIZE_FIELD_OPTION_VALUE) h on h.FIELD_OPTION_VALUE_ID = ");
            sb.append(" e.FIELD_OPTION_VALUE_ID");
            sb.append(" where 1 = 1");
            sb.append("  and a.COMPANY_SITE_ID = :p_company_site_id");
            sb.append("  and a.CUSTOMER_LIST_ID = :p_customer_list_id");
            sb.append("  and a.CUSTOMER_ID = :p_customer_id");

            sb.append(" AND e.FUNCTION_CODE = 'CUSTOMER'");

            SQLQuery query = session.createSQLQuery(sb.toString());

            query.setParameter("p_company_site_id", companySiteId);
            query.setParameter("p_customer_list_id", customerListId);
            query.setParameter("p_customer_id", customerId);

            query.addScalar("companySiteId", new LongType());
            query.addScalar("customerListId", new LongType());
            query.addScalar("customerId", new LongType());
            query.addScalar("title", new StringType());
            query.addScalar("type", new StringType());
            query.addScalar("valueCombobox", new StringType());
            query.addScalar("valueCheckbox", new ShortType());
            query.addScalar("valueDate", new DateType());
            query.addScalar("valueNumber", new LongType());
            query.addScalar("valueText", new StringType());

            query.setResultTransformer(Transformers.aliasToBean(CustomerDetailRequestDTO.class));

            List<CustomerDetailRequestDTO> data = query.list();
            resultDTO.setData(data);
            resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
            resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
        } catch (Exception e) {
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
        } finally {
            session.close();
        }

        return resultDTO;
    }

    public Date getSysdate() {
        try {
            Query query = entityManager.createNativeQuery("SELECT to_char(sysdate, 'dd/MM/YYYY hh24:mi:ss') FROM DUAL ");
            List list = query.getResultList();
            if (list != null && list.size() > 0) {
                return DataUtil.convertStringToDateDDMMYYYYHHMISS(DataUtil.safeToString(list.get(0)));
            }
        } catch (Exception e) {
            //logger.info(e.getMessage(), e);
            e.printStackTrace();
        }
        return new Date();
    }

    // ------------- customer list ----------------- //

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO getAllCustomerList(int page, int pageSize, String sort, Long companySiteId) {
        ResultDTO resultDTO = new ResultDTO();
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

        Session session = sessionFactory.openSession();
        session.beginTransaction();

        if (DataUtil.isNullOrZero(companySiteId)) {
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
            return resultDTO;
        }

        try {
//            StringBuilder  sb = new StringBuilder();
//             sb.append(SQLBuilder.getSqlQueryById(SQLBuilder.SQL_MODULE_CAMPAIGN_MNG, "search-campaign-customer-by-params"));

            StringBuilder sb = new StringBuilder();

            sb.append("SELECT");
            sb.append("    CUSTOMER_LIST_ID customerListId,");
            sb.append("    COMPANY_SITE_ID companySiteId,");
            sb.append("    CUSTOMER_LIST_CODE customerListCode,");
            sb.append("    CUSTOMER_LIST_NAME customerListName,");
            sb.append("    STATUS status,");
            sb.append("    CREATE_BY createBy,");
            sb.append("    CREATE_AT createAt,");
            sb.append("    UPDATE_BY updateBy,");
            sb.append("    UPDATE_AT updateAt,");
            sb.append("    SOURCE source,");
            sb.append("    DEPT_CREATE deptCreate");
            sb.append(" FROM CUSTOMER_LIST");
            sb.append(" WHERE 1 = 1");
            sb.append("  AND STATUS = 1");
            sb.append("  AND COMPANY_SITE_ID = :p_company_site_id");

            sb.append(" ORDER BY CREATE_AT DESC");

            SQLQuery query = session.createSQLQuery(sb.toString());

            query.setParameter("p_company_site_id", companySiteId);

            query.addScalar("customerListId", new LongType());
            query.addScalar("companySiteId", new LongType());
            query.addScalar("customerListCode", new StringType());
            query.addScalar("customerListName", new StringType());
            query.addScalar("status", new ShortType());
            query.addScalar("createBy", new StringType());
            query.addScalar("createAt", new DateType());
            query.addScalar("updateBy", new StringType());
            query.addScalar("updateAt", new DateType());
            query.addScalar("source", new StringType());
            query.addScalar("deptCreate", new StringType());

            query.setResultTransformer(Transformers.aliasToBean(CustomerListDTO.class));
            int count = 0;
            List<CustomerListDTO> dtoList = query.list();
            if (dtoList.size() > 0) {
                count = query.list().size();
            }

            Pageable pageable = PageRequest.of(page, pageSize, Sort.by(Sort.Order.desc(sort)));
            if (pageable != null) {
                query.setFirstResult(pageable.getPageNumber() * pageable.getPageSize());
                query.setMaxResults(pageable.getPageSize());
            }

            List<CustomerListDTO> data = query.list();
            Page<CustomerListDTO> dataPage = new PageImpl<>(data, pageable, count);
            resultDTO.setData(dataPage);
            resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
            resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
        } catch (Exception e) {
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
        } finally {
            session.close();
        }

        return resultDTO;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO createCustomerList(CustomerListDTO customerListDTO, String userName) {
        ResultDTO resultDTO = new ResultDTO();
        CustomerListMapper customerListMapper = new CustomerListMapper();
        CustomerList customerList = new CustomerList();

        try {
            if (customerListDTO != null) {
                // insert
                CustomerList findCustomer = customerListRepository.findByCustomerListCode(customerListDTO.getCustomerListCode());
                if (findCustomer == null) {
                    customerListDTO.setCreateBy(userName);

                    customerList = customerListMapper.toPersistenceBean(customerListDTO);
                    customerListRepository.save(customerList);

                    resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
                    resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
                } else {
                    resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
                    resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
                }
            } else {
                resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
                resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return resultDTO;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO updateCustomerList(CustomerListDTO customerListDTO) {
        ResultDTO resultDTO = new ResultDTO();
        CustomerListMapper customerListMapper = new CustomerListMapper();

        try {
            if (customerListDTO != null) {
                // update
                CustomerList customerList = customerListRepository.findByCustomerListIdAndCompanySiteId(customerListDTO.getCustomerListId(), customerListDTO.getCompanySiteId());

                if (customerList != null) {
                    customerList = customerListMapper.toPersistenceBean(customerListDTO);
                    customerListRepository.save(customerList);

                    resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
                    resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
                } else {
                    resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
                    resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
                }
            } else {
                resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
                resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return resultDTO;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO deleteCustomerList(CustomerListDTO customerListDTO) {
        ResultDTO resultDTO = new ResultDTO();

        try {
            // delete
            if (DataUtil.isNullOrZero(campaignCustomerListRepository.campaignCount(customerListDTO.getCustomerListId()))) {

                customerListRepository.deleteCustomerList(customerListDTO.getCustomerListId(), customerListDTO.getCompanySiteId());

                customerListMappingRepository.deleteMappingByCustomerListId(customerListDTO.getCustomerListId(), customerListDTO.getCompanySiteId());

                resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
                resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
            } else {
                resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
                resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return resultDTO;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO deleteCustomerListIds(CustomerRequestDTO customerRequestDTO) {
        ResultDTO resultDTO = new ResultDTO();
        try {
            if (customerRequestDTO != null) {
                if (DataUtil.isNullOrZero(campaignCustomerListRepository.campaignIdsCount(customerRequestDTO.getIds()))) {
                    customerListRepository.deleteCustomerListIds(customerRequestDTO.getIds(), customerRequestDTO.getCompanySiteId());

                    customerListMappingRepository.deleteMappingByCustomerListIds(customerRequestDTO.getIds(), customerRequestDTO.getCompanySiteId());

                    resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
                    resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
                } else {
                    resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
                    resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
                }
            } else {
                resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
                resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultDTO;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO searchCustomerList(SearchCustomerRequestDTO searchCustomerRequestDTO) {
        ResultDTO resultDTO = new ResultDTO();
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

        Session session = sessionFactory.openSession();
        session.beginTransaction();

        if (DataUtil.isNullOrEmpty(searchCustomerRequestDTO.getCompanySiteId())) {
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
            return resultDTO;
        }

        try {
//            StringBuilder  sb = new StringBuilder();
//             sb.append(SQLBuilder.getSqlQueryById(SQLBuilder.SQL_MODULE_CAMPAIGN_MNG, "search-campaign-customer-by-params"));
            StringBuilder sb = new StringBuilder();

            sb.append("SELECT");
            sb.append("    CUSTOMER_LIST_ID customerListId,");
            sb.append("    COMPANY_SITE_ID companySiteId,");
            sb.append("    CUSTOMER_LIST_CODE customerListCode,");
            sb.append("    CUSTOMER_LIST_NAME customerListName,");
            sb.append("    STATUS status,");
            sb.append("    CREATE_BY createBy,");
            sb.append("    CREATE_AT createAt,");
            sb.append("    UPDATE_BY updateBy,");
            sb.append("    UPDATE_AT updateAt,");
            sb.append("    SOURCE source,");
            sb.append("    DEPT_CREATE deptCreate");
            sb.append(" FROM CUSTOMER_LIST");
            sb.append(" WHERE 1 = 1");
            sb.append("  AND STATUS = 1");
            sb.append("  AND COMPANY_SITE_ID = :p_company_site_id");

            sb.append(" AND CREATE_AT BETWEEN to_date(:p_date_from, 'YYYYMMDD') AND to_date(:p_date_to, 'YYYYMMDD')");

            if (!DataUtil.isNullOrEmpty(searchCustomerRequestDTO.getCustomerListCode())) {
                sb.append(" AND CUSTOMER_LIST_CODE LIKE :p_list_code");
            }
            if (!DataUtil.isNullOrEmpty(searchCustomerRequestDTO.getCustomerListName())) {
                sb.append(" AND CUSTOMER_LIST_NAME LIKE :p_list_name");
            }

            SQLQuery query = session.createSQLQuery(sb.toString());

            query.setParameter("p_company_site_id", searchCustomerRequestDTO.getCompanySiteId());
            query.setParameter("p_date_from", searchCustomerRequestDTO.getConvertedDateFrom());
            query.setParameter("p_date_to", searchCustomerRequestDTO.getConvertedDateTo());

            if (!DataUtil.isNullOrEmpty(searchCustomerRequestDTO.getCustomerListCode())) {
                query.setParameter("p_list_code", "%" +
                        searchCustomerRequestDTO.getCustomerListCode()
                                .replace("\\", "\\\\")
                                .replaceAll("%", "\\%")
                                .replaceAll("_", "\\_")
                        + "%");
            }

            if (!DataUtil.isNullOrEmpty(searchCustomerRequestDTO.getCustomerListName())) {
                query.setParameter("p_list_name", "%" +
                        searchCustomerRequestDTO.getCustomerListName()
                                .replace("\\", "\\\\")
                                .replaceAll("%", "\\%")
                                .replaceAll("_", "\\_")
                        + "%");
            }

            query.addScalar("customerListId", new LongType());
            query.addScalar("companySiteId", new LongType());
            query.addScalar("customerListCode", new StringType());
            query.addScalar("customerListName", new StringType());
            query.addScalar("status", new ShortType());
            query.addScalar("createBy", new StringType());
            query.addScalar("createAt", new DateType());
            query.addScalar("updateBy", new StringType());
            query.addScalar("updateAt", new DateType());
            query.addScalar("source", new StringType());
            query.addScalar("deptCreate", new StringType());

            query.setResultTransformer(Transformers.aliasToBean(CustomerListDTO.class));
            int count = 0;
            List<CustomerListDTO> dtoList = query.list();
            if (dtoList.size() > 0) {
                count = query.list().size();
            }

            Pageable pageable = PageRequest.of(searchCustomerRequestDTO.getPage(), searchCustomerRequestDTO.getPageSize(), Sort.by(searchCustomerRequestDTO.getSort()));
            if (pageable != null) {
                query.setFirstResult(pageable.getPageNumber() * pageable.getPageSize());
                query.setMaxResults(pageable.getPageSize());
            }

            List<CustomerListDTO> data = query.list();
            Page<CustomerListDTO> dataPage = new PageImpl<>(data, pageable, count);
            resultDTO.setData(dataPage);
            resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
            resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
        } catch (
                Exception e) {
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
        } finally {
            session.close();
        }

        return resultDTO;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public CustomerList getLatestCreated(Long companySiteId) {
        return customerListRepository.latestCreated(companySiteId);
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO getCustomerContact(CustomerContactDTO customer) {
        ResultDTO result = new ResultDTO();

        try {
            List<CustomerContact> data = customerContactRepository.findByCustomerIdAndAndContactTypeAndContact(customer.getCustomerId(), customer.getContactType(), customer.getContact(), SQLBuilder.buildPageable(customer));

            if (customer != null) {
                result.setErrorCode(Constants.ApiErrorCode.SUCCESS);
                result.setDescription("customer contact data");
                result.setListData(data);
                result.setTotalRow(customerContactRepository.findByCustomerIdAndAndContactTypeAndContact(customer.getCustomerId(), customer.getContactType(), customer.getContact(), null).size());

            } else {
                result.setErrorCode(Constants.ApiErrorCode.ERROR);
                result.setDescription("customer contact data null");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO getCustomerRecall(Long campaignId, Long customerId) {
        ResultDTO result = new ResultDTO();

        try {
            Long data = campaignCustomerRepository.getCustomerRecall(campaignId, customerId);

            if (data != null) {
                result.setErrorCode(Constants.ApiErrorCode.SUCCESS);
                result.setDescription("campaign customer data");
                result.setData(data);

            } else {
                result.setErrorCode(Constants.ApiErrorCode.ERROR);
                result.setDescription("campaign customer data null");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public List<DynamicExcelHeaderDTO> getDynamicHeader(Long companySiteId) {
        List<DynamicExcelHeaderDTO> headerList;
        try {
            //String sql = SQLBuilder.getSqlQueryById(SQLBuilder.SQL_MODULE_CAMPAIGN_CUSTOMER_MNG, "get-dynamic-header");
            StringBuilder sb = new StringBuilder();

            sb.append(" select CUSTOMIZE_FIELD_ID customizeFieldId,");
            sb.append(" SITE_ID companySiteId,");
            sb.append(" FUNCTION_CODE functionCode,");
            sb.append(" CREATE_BY createBy,");
            sb.append(" CREATE_DATE createDate,");
            sb.append(" UPDATE_BY updateBy,");
            sb.append(" UPDATE_DATE updateDate,");
            sb.append(" STATUS status,");
            sb.append(" TYPE type,");
            sb.append(" TITLE title,");
            sb.append(" PLACEHOLDER placeholder,");
            sb.append(" DESCRIPTION description,");
            sb.append(" POSITION position,");
            sb.append(" REQUIRED required,");
            sb.append(" FIELD_OPTIONS_ID fieldOptionsId,");
            sb.append(" REGEXP_FOR_VALIDATION regexpForValidation,");
            sb.append(" MAX_LENGTH maxLength,");
            sb.append(" MIN min,");
            sb.append(" MAX max,");
            sb.append(" MIN_LENGTH minLength,");
            sb.append(" ACTIVE active");
            sb.append(" from customize_fields");
            sb.append(" where function_code = 'CUSTOMER'");
            sb.append(" and site_id = :p_company_site_id");

            Map<String, Object> param = new HashMap<>();
            param.put("p_company_site_id", companySiteId);
            headerList = namedParameterJdbcTemplate.query(sb.toString(), param, new BeanPropertyRowMapper<>(DynamicExcelHeaderDTO.class));
        } catch (Exception e) {
            return null;
        }
        return headerList;
    }

    @Override
    public void buildTemplate(Long companySiteId) {
        try {
            List<DynamicExcelHeaderDTO> headerList = getDynamicHeader(companySiteId);
            FileInputStream fis = new FileInputStream(ResourceUtils.getFile("classpath:templates/import_customer_template.xlsx"));
            XSSFWorkbook workbook = new XSSFWorkbook(fis);
            XSSFSheet sheet = workbook.getSheetAt(0);
            Row row = sheet.getRow(2);
            Cell cell = row.createCell(row.getPhysicalNumberOfCells());
            cell.setCellType(CellType.STRING);
            cell.setCellValue("test");
            FileOutputStream fos = new FileOutputStream(ResourceUtils.getFile("classpath:templates/import_customer_template.xlsx"));
            workbook.write(fos);
            fos.close();
            workbook.close();
        } catch (Exception e) {

        }
    }

    @Override
    public List<CustomizeFieldDTO> getCustomizeField(Long customerId) {
        List<CustomizeFieldDTO> customizeFieldDTOList;
        try {
            //String sql = SQLBuilder.getSqlQueryById(SQLBuilder.SQL_MODULE_CAMPAIGN_MNG, "get-customize-field");

            StringBuilder sb = new StringBuilder();

            sb.append(" select CUSTOMIZE_FIELD_OBJECT_ID customizeFieldObjectId,");
            sb.append(" OBJECT_ID objectId,");
            sb.append(" CUSTOMIZE_FIELDS_ID customizeFieldId,");
            sb.append(" VALUE_TEXT valueText,");
            sb.append(" VALUE_NUMBER valueNumber,");
            sb.append(" VALUE_DATE valueDate,");
            sb.append(" VALUE_CHECKBOX valueCheckbox,");
            sb.append(" CREATE_BY createBy,");
            sb.append(" CREATE_DATE createDate,");
            sb.append(" UPDATE_BY updateBy,");
            sb.append(" UPDATE_DATE updateDate,");
            sb.append(" STATUS status,");
            sb.append(" FIELD_OPTION_VALUE_ID fieldOptionValueId,");
            sb.append(" TITLE title,");
            sb.append(" FUNCTION_CODE functionCode");
            sb.append(" from customize_field_object");
            sb.append(" where function_code = 'CUSTOMER' and object_id = :p_customer_id");


            Map<String, Object> param = new HashMap<>();
            param.put("p_customer_id", customerId);
            customizeFieldDTOList = namedParameterJdbcTemplate.query(sb.toString(), param, new BeanPropertyRowMapper<>(CustomizeFieldDTO.class));
        } catch (Exception e) {
            return null;
        }
        return customizeFieldDTOList;
    }


    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public List<CustomerListDTO> getCustomerListInfo(CampaignCustomerDTO campaignCustomerDTO) {
        List<CustomerListDTO> customerList;
        try {
            //String sql = SQLBuilder.getSqlQueryById(SQLBuilder.SQL_MODULE_CAMPAIGN_MNG, "search-customer-list-info-from-customer-list");
            // BuildMyString.com generated code. Please enjoy your string responsibly.

            StringBuilder sb = new StringBuilder();

            sb.append(" with totalCustomer as (");
            sb.append(" select clm.customer_list_id,");
            sb.append(" clm.company_site_id,");
            sb.append(" count(clm.customer_id) total");
            sb.append(" from customer_list_mapping clm");
            sb.append(" inner join customer c on clm.customer_id = c.customer_id");
            sb.append(" where c.status = 1");
            sb.append(" group by clm.customer_list_id,clm.company_site_id");
            sb.append(" ), customerInteractive as (");
            sb.append(" select customer_list_id,");
            sb.append(" company_site_id,");
            sb.append(" count(customer_id) tt");
            sb.append(" from campaign_customer where campaign_id = :p_campaign_id and status <> 0");
            sb.append(" group by customer_list_id, company_site_id");
            sb.append(" ), customerNotInteractive as (");
            sb.append(" select customer_list_id,");
            sb.append(" company_site_id,");
            sb.append(" count(customer_id) ktt");
            sb.append(" from campaign_customer where campaign_id = :p_campaign_id and status = 0");
            sb.append(" and in_campaign_status = 1");
            sb.append(" group by customer_list_id, company_site_id");
            sb.append(" ), datas as (");
            sb.append(" select customer_list_code customerListCode,");
            sb.append(" customer_list_name customerListName,");
            sb.append(" nvl(total, 0) totalCusInList,");
            sb.append(" nvl(tt, 0) totalCusInteract,");
            sb.append(" nvl(ktt, 0) totalCusNotInteract");
            sb.append(" from customer_list cl");
            sb.append(" left join totalCustomer tc on (cl.customer_list_id = tc.customer_list_id and cl.company_site_id = tc.company_site_id)");
            sb.append(" left join customerInteractive ci on (cl.customer_list_id = ci.customer_list_id and cl.company_site_id = ci.company_site_id)");
            sb.append(" left join customerNotInteractive cni on (cl.customer_list_id = cni.customer_list_id and cl.company_site_id = cni.company_site_id)");
            sb.append(" where cl.company_site_id = :p_company_site_id");
            sb.append(" )");
            sb.append(" select * from");
            sb.append(" (");
            sb.append("    select a.*, rownum r__");
            sb.append("    from");
            sb.append("    (");
            sb.append("        select * from datas");
            sb.append("        order by customerListCode");
            sb.append("    ) a");
            sb.append("    where rownum < ((:p_page_number * :p_page_size) + 1 )");
            sb.append(" )");
            sb.append(" where r__ >= (((:p_page_number-1) * :p_page_size) + 1)");


            Map<String, Object> param = new HashMap<>();
            param.put("p_campaign_id", campaignCustomerDTO.getCampaignId());
            param.put("p_company_site_id", campaignCustomerDTO.getCompanySiteId());
            param.put("p_page_number", campaignCustomerDTO.getPage());
            param.put("p_page_size", campaignCustomerDTO.getPageSize());
            customerList = namedParameterJdbcTemplate.query(sb.toString(), param, new BeanPropertyRowMapper<>(CustomerListDTO.class));
        } catch (Exception e) {
            return null;
        }
        return customerList;
    }

    @Override
    public List<CustomerDTO> getIndividualCustomerInfo(CampaignCustomerDTO campaignCustomerDTO) {
        List<CustomerDTO> customerList;
        try {
            //String sql = SQLBuilder.getSqlQueryById(SQLBuilder.SQL_MODULE_CAMPAIGN_MNG, "search-individual-customer");
            // BuildMyString.com generated code. Please enjoy your string responsibly.

            StringBuilder sb = new StringBuilder();

            sb.append("with cusPhone as (");
            sb.append(" select customer_id cusId,");
            sb.append(" contact phone");
            sb.append(" from customer_contact cc");
            sb.append(" where cc.contact_type = 5");
            sb.append(" and status = 1");
            sb.append(" ), cusEmail as (");
            sb.append(" select customer_id cusId,");
            sb.append(" contact email");
            sb.append(" from customer_contact cc");
            sb.append(" where cc.contact_type = 2");
            sb.append(" and status = 1");
            sb.append(" ), datas as (");
            sb.append(" select c.customer_id customerId,");
            sb.append(" c.name,");
            sb.append(" cP.phone,");
            sb.append(" cE.email,");
            sb.append(" c.customer_type cusType,");
            sb.append(" c.company_name compName,");
            sb.append(" c.current_address currentAddress,");
            sb.append(" c.description");
            sb.append(" from customer c");
            sb.append(" left join cusPhone cP on c.customer_id = cP.cusId");
            sb.append(" left join cusEmail cE on c.customer_id = cE.cusId");
            sb.append(" )");
            sb.append(" select * from");
            sb.append(" (");
            sb.append("    select a.*, rownum r__");
            sb.append("    from");
            sb.append("    (");
            sb.append("        select * from datas");
            sb.append("        order by datas.name");
            sb.append("    ) a");
            sb.append("    where rownum < ((:p_page_number * :p_page_size) + 1 )");
            sb.append(" )");
            sb.append(" where r__ >= (((:p_page_number-1) * :p_page_size) + 1)");

            Map<String, Object> param = new HashMap<>();
            param.put("p_page_number", campaignCustomerDTO.getPage());
            param.put("p_page_size", campaignCustomerDTO.getPageSize());
            customerList = namedParameterJdbcTemplate.query(sb.toString(), param, new BeanPropertyRowMapper<>(CustomerDTO.class));
        } catch (Exception e) {
            return null;
        }
        return customerList;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public List<Customer> findAllByCondition(Long siteId, Date endTime) {
        return customerRepository.findAllByCondition(siteId, endTime);
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public Customer update(Customer c) {
        return customerRepository.save(c);
    }

    @Override
    public List<Customer> searchByQuery(String queryString) {
        RSQLVisitor<CriteriaQuery<Customer>, EntityManager> visitor = new JpaCriteriaQueryVisitor<>();
        CriteriaQuery<Customer> query;
        query = getCriteriaQuery(queryString, visitor);
        List<Customer> resultList = entityManager.createQuery(query).getResultList();
        if (resultList == null || resultList.isEmpty()){
            return Collections.emptyList();
        }
        return resultList;
    }

    @Override
    public Long countByQuery(String queryString) {
        RSQLVisitor<CriteriaQuery<Long>, EntityManager> visitor = new JpaCriteriaCountQueryVisitor<Customer>();
        CriteriaQuery<Long> query;
        query = getCriteriaQuery(queryString, visitor);

        return entityManager.createQuery(query).getSingleResult();
    }
    private <T> CriteriaQuery<T> getCriteriaQuery(String queryString, RSQLVisitor<CriteriaQuery<T>, EntityManager> visitor) {
        Node rootNode;
        CriteriaQuery<T> query;
        try {
            rootNode = new RSQLParser().parse(queryString);
            query = rootNode.accept(visitor, entityManager);
        } catch (Exception e){
            e.printStackTrace();
            throw new IllegalArgumentException(e.getMessage());
        }
        return query;
    }
}
