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.*;
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.*;
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.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.reflect.Array;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class CustomerServiceImpl implements CustomerService {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomerServiceImpl.class);

    @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;

    @Autowired
    CustomizeFieldsRepository customizeFieldsRepository;

    @Autowired
    CustomizeFieldObjectRepository customizeFieldObjectRepository;

    @Autowired
    CustomizeFieldOptionValueRepository customizeFieldOptionValueRepository;

    @Autowired
    ApParamRepository apParamRepository;

    @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.trim().replace("\\", "\\\\")
                                .replaceAll("%", "\\%")
                                .replaceAll("_", "\\_")
                        + "%");
            }

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

            if (!DataUtil.isNullOrEmpty(email)) {
                query.setParameter("p_email", "%" +
                        email.trim().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
    @Transactional(DataSourceQualify.CCMS_FULL)
    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) {
        ApParam apParam = apParamRepository.getCustomerListSeq();

        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
        Date currentDate = new Date(dateFormat.format(new Date()));
        Date oldDate = new Date(apParam.getDescription());
        Long newDay = (currentDate.getTime() - oldDate.getTime()) / (1000 * 60 * 60 * 24);
        String convertDate = dateFormat.format(new Date());
        String[] dateArray = convertDate.split("/");

        if (customerListDTO.getCustomerListCode().trim().length() == 0) {
            if (newDay == 0) {
                apParamRepository.updateCustomerListSeq(String.valueOf(Integer.parseInt(apParam.getParValue()) + 1), apParam.getDescription());
                customerListDTO.setCustomerListCode(dateArray[0] + dateArray[2] + dateArray[1] + "_" + (Integer.parseInt(apParam.getParValue()) + 1));
            } else {
                apParamRepository.updateCustomerListSeq("1", dateFormat.format(new Date()));
                customerListDTO.setCustomerListCode(dateArray[0] + dateArray[2] + dateArray[1] + "_1");
            }
        }

        // THÍM NÀO MERGE CONFLICT THÌ GIỮ LẠI HỘ E CÁI METHOD NÀY VỚI
        // VIẾT ĐI VIẾT LẠI 4 LẦN RỒI ĐẤY
        ResultDTO resultDTO = new ResultDTO();
        try {
            CustomerList cl = customerListRepository.findByCustomerListCode(customerListDTO.getCustomerListCode());
            if (cl != null) {
                resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
                resultDTO.setDescription("Entity exists");
                return resultDTO;
            } else {
                cl = new CustomerList();
                cl.setCustomerListCode(customerListDTO.getCustomerListCode());
                cl.setCustomerListName(customerListDTO.getCustomerListName());
                cl.setStatus((short) 1);
                cl.setCreateBy(userName);
                cl.setCreateAt(new Date());
                cl.setUpdateBy(null);
                cl.setUpdateAt(null);
                cl.setSource(null);
                cl.setDeptCreate(null);
                cl.setCompanySiteId(customerListDTO.getCompanySiteId());
                resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
                resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
                resultDTO.setData(customerListRepository.save(cl));
                return resultDTO;
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage());
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription("Error");
            return resultDTO;
        }
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO updateCustomerList(CustomerListDTO customerListDTO, String userName) {
        ResultDTO resultDTO = new ResultDTO();

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

                if (customerList != null) {
//                    customerList.setCreateBy(customerListDTO.getCreateBy());
                    customerList.setCompanySiteId(customerListDTO.getCompanySiteId());
//                    customerList.setCreateAt(customerListDTO.getCreateAt());
                    customerList.setCustomerListCode(customerListDTO.getCustomerListCode());
                    customerList.setCustomerListName(customerListDTO.getCustomerListName());
                    customerList.setDeptCreate(customerListDTO.getDeptCreate());
                    customerList.setStatus(customerList.getStatus());
                    customerList.setUpdateBy(userName);
                    customerList.setUpdateAt(new Date());
                    customerList.setSource(customerListDTO.getSource());
                    customerList.setCustomerListId(customerListDTO.getCustomerListId());


                    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("    a.CUSTOMER_LIST_ID customerListId,");
            sb.append("    a.COMPANY_SITE_ID companySiteId,");
            sb.append("    a.CUSTOMER_LIST_CODE customerListCode,");
            sb.append("    a.CUSTOMER_LIST_NAME customerListName,");
            sb.append("    a.STATUS status,");
            sb.append("    a.CREATE_BY createBy,");
            sb.append("    a.CREATE_AT createAt,");
            sb.append("    a.UPDATE_BY updateBy,");
            sb.append("    a.UPDATE_AT updateAt,");
            sb.append("    a.SOURCE source,");
            sb.append("    a.DEPT_CREATE deptCreate,");
            sb.append("    b.count count");
            sb.append(" FROM CUSTOMER_LIST a");
            sb.append(" LEFT JOIN (SELECT COUNT(CAMPAIGN_ID) as count, CUSTOMER_LIST_ID");
            sb.append(" FROM CAMPAIGN_CUSTOMERLIST");
            sb.append(" GROUP BY CUSTOMER_LIST_ID) b");
            sb.append(" ON a.CUSTOMER_LIST_ID = b.CUSTOMER_LIST_ID");
            sb.append(" WHERE 1 = 1");
            sb.append("  AND a.STATUS = 1");
            sb.append("  AND a.COMPANY_SITE_ID = :p_company_site_id");

            sb.append(" AND to_date(CREATE_AT, 'DD-MM-RR') >= to_date(:p_date_from, 'YYYYMMDD') AND to_date(CREATE_AT, 'DD-MM-RR') <= to_date(:p_date_to, 'YYYYMMDD')");

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

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

            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().trim()
                                .replace("\\", "\\\\")
                                .replaceAll("%", "\\%")
                                .replaceAll("_", "\\_")
                        + "%");
            }

            if (!DataUtil.isNullOrEmpty(searchCustomerRequestDTO.getCustomerListName())) {
                query.setParameter("p_list_name", "%" +
                        searchCustomerRequestDTO.getCustomerListName().trim()
                                .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.addScalar("count", 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
    @Transactional(DataSourceQualify.CCMS_FULL)
    public List<CustomizeFields> getDynamicHeader(Long companySiteId) {
        LOGGER.info("------------------GET DYNAMIC HEADER-------------------");
        List<CustomizeFields> headerList;
        try {
            headerList = customizeFieldsRepository.findCustomizeFieldsByFunctionCodeEqualsAndStatusAndActiveAndSiteId("CUSTOMER", 1L, 1L, companySiteId);
        } catch (Exception e) {
            LOGGER.info(e.getMessage());
            return null;
        }
        return headerList;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public Map<String, Object> readAndValidateCustomer(String path, List<CustomizeFields> dynamicHeader, UserSession userSession, Long customerListId) {
        LOGGER.info("------------READ AND VALIDATE--------------");
        Locale locale = new Locale("vi", "VN");
        DataFormatter dataFormat = new DataFormatter();
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
        Map<String, Object> result = new HashMap<>();
        StringBuilder sb = new StringBuilder();
        boolean validateOk = false;
        try {

            //<editor-fold desc="Khởi tạo mảng header tĩnh" defaultstate="collapsed">

            List<CustomizeFields> header = new ArrayList<>();
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.no", locale)));
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.fullname", locale)));
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.mainPhone", locale)));
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.secondPhone", locale)));
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.email", locale)));
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.address", locale)));
            header.add(new CustomizeFields("combobox", BundleUtils.getLangString("customer.cusType", locale)));
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.companyName", locale)));
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.description", locale)));
            header.add(new CustomizeFields("combobox", BundleUtils.getLangString("customer.callAllowed", locale)));
            header.add(new CustomizeFields("combobox", BundleUtils.getLangString("customer.emailAllowed", locale)));
            header.add(new CustomizeFields("combobox", BundleUtils.getLangString("customer.smsAllowed", locale)));

            header.addAll(dynamicHeader);
            //</editor-fold>

            File file = new File(path);
            FileInputStream fis = new FileInputStream(file);
            XSSFWorkbook workbook = new XSSFWorkbook(fis);
            Sheet sheet = workbook.getSheetAt(0);
            Row row = sheet.getRow(3);

            //<editor-fold desc="Tạo style cho cột kết quả" defaultstate="collapsed">
            Font resultFont = workbook.createFont();
            resultFont.setBold(true);
            resultFont.setFontHeightInPoints((short) 11);
            CellStyle resultStyle = workbook.createCellStyle();
            resultStyle.setFont(resultFont);
            resultStyle.setBorderLeft(BorderStyle.THIN);
            resultStyle.setBorderRight(BorderStyle.THIN);
            resultStyle.setBorderBottom(BorderStyle.THIN);
            resultStyle.setBorderTop(BorderStyle.THIN);
            //</editor-fold>

            //<editor-fold desc="Kiểm tra header của template" defaultstate="collapsed">
            for (int i = 0; i < header.size(); i++) {
                Cell cell = row.getCell(i);
                if (!cell.getStringCellValue().equals(header.get(i).getTitle().split("#")[0])) {
                    result.put("file", file);
                    result.put("message", BundleUtils.getLangString("customer.invalidTemplate", locale));
                    return result;
                }
            }
            //</editor-fold>

            List<Object[]> rawDataList = new ArrayList<>();

            //<editor-fold desc="Kiểm tra file dữ liệu rỗng" defaultstate="collapsed">
            if (sheet.getPhysicalNumberOfRows() == 3) {
                result.put("message", BundleUtils.getLangString("customer.noData", locale));
                result.put("file", file);
                return result;
            } else {
                Cell resultCell = sheet.getRow(3).createCell(sheet.getRow(3).getPhysicalNumberOfCells());
                resultCell.setCellValue(BundleUtils.getLangString("customer.result", locale));
                resultCell.setCellStyle(resultStyle);
            }
            //</editor-fold>

            //<editor-fold desc="Đọc dữ liệu từng dòng 1" defaultstate="collapsed">
            for (int i = 4; i < sheet.getPhysicalNumberOfRows(); i++) {
                Row dataRow = sheet.getRow(i);
                if (dataRow != null) {
                    Object[] obj = new Object[row.getPhysicalNumberOfCells()];
                    for (int j = 0; j < row.getPhysicalNumberOfCells(); j++) {
                        Cell dataCell = dataRow.getCell(j);
                        if (dataCell != null) {
                            obj[j] = dataFormat.formatCellValue(dataCell);
                        } else {
                            Cell headerCell = row.getCell(j);
                            if (headerCell.getStringCellValue().equals(BundleUtils.getLangString("customer.cusType", locale))) {
                                obj[j] = BundleUtils.getLangString("customer.cusType.normal", locale);
                            } else if (headerCell.getStringCellValue().equals(BundleUtils.getLangString("customer.callAllowed", locale)) || headerCell.getStringCellValue().equals(BundleUtils.getLangString("customer.emailAllowed", locale))
                                    || headerCell.getStringCellValue().equals(BundleUtils.getLangString("customer.smsAllowed", locale))) {
                                obj[j] = BundleUtils.getLangString("customer.yes", locale);
                                break;
                            } else {
                                obj[j] = null;
                            }
                        }
                    }
                    rawDataList.add(obj);
                }
            }
            //</editor-fold>

            //<editor-fold desc="Validate dữ liệu" defaultstate="collapsed">

            for (int i = 0; i < rawDataList.size(); i++) {
                if (rawDataList.get(i).length > 1 && rawDataList.get(i)[1] != null && !rawDataList.get(i)[1].toString().trim().equals("")) {
                    String str = validateLength(BundleUtils.getLangString("customer.fullname", locale).split("#")[0], rawDataList.get(i)[1].toString(), 1000, locale);
                    if (!str.equals("")) {
                        sb.append(str);
                    }
                } else sb.append(BundleUtils.getLangString("customer.nameRequired"));
                if (rawDataList.get(i).length > 4
                        && rawDataList.get(i)[2] != null
                        && !rawDataList.get(i)[2].toString().trim().equals("")
                        && rawDataList.get(i)[3] != null
                        && !rawDataList.get(i)[3].toString().trim().equals("")
                        && rawDataList.get(i)[4] != null
                        && !rawDataList.get(i)[4].toString().trim().equals("")) {
                    String str = validatePhone(rawDataList.get(i)[2].toString().trim(), locale);
                    str.concat(validateLength(BundleUtils.getLangString("customer.secondPhone", locale).split("#")[0], rawDataList.get(i)[3].toString(), 50, locale));
                    if (!validateEmail(rawDataList.get(i)[4].toString().trim())) {
                        str.concat(BundleUtils.getLangString("customer.emailInvalid", locale));
                    } else {
                        str.concat(validateDuplicateEmail(rawDataList.get(i)[4].toString().trim(), locale));
                    }
                    sb.append(validateLength(BundleUtils.getLangString("customer.email", locale).split("#")[0], rawDataList.get(i)[4].toString(), 50, locale));
                    sb.append(str);
                } else {
                    sb.append(BundleUtils.getLangString("customer.invalidCustomer", locale));
                }
                if (rawDataList.get(i).length > 5 && rawDataList.get(i)[5] != null) {
                    sb.append(validateLength(BundleUtils.getLangString("customer.address", locale).split("#")[0], rawDataList.get(i)[5].toString(), 500, locale));
                }
                if (rawDataList.get(i).length > 7 && rawDataList.get(i)[7] != null) {
                    sb.append(validateLength(BundleUtils.getLangString("customer.companyName", locale).split("#")[0], rawDataList.get(i)[7].toString(), 100, locale));
                }
                if (rawDataList.get(i).length > 8 && rawDataList.get(i)[8] != null) {
                    sb.append(validateLength(BundleUtils.getLangString("customer.description", locale).split("#")[0], rawDataList.get(i)[8].toString(), 2000, locale));
                }
//                for (int j = 12; j < header.size(); j++) {
//                    if (rawDataList.get(i).length > j && rawDataList.get(i)[j] != null) {
//                        if (header.get(j).getType().equals("text")) {
//                            sb.append(validateDynamicLength(header.get(j).getTitle(), rawDataList.get(i)[j].toString(), header.get(j).getMinLength(), header.get(j).getMaxLength(), locale));
//                        } else if (header.get(j).getType().equals("date")) {
//                            sb.append(validateUsingRegexp(header.get(j).getTitle(), rawDataList.get(i)[j].toString(), header.get(j).getRegexpForValidation(), locale));
//                        } else if (header.get(j).getType().equals("number")) {
//                            sb.append(validateDynamicLength(header.get(j).getTitle(), rawDataList.get(i)[j].toString(), header.get(j).getMin(), header.get(j).getMax(), locale));
//                        }
//                    }
//                }
                Row dataRow = sheet.getRow(4 + i);
                Cell resultCell = dataRow.createCell(row.getPhysicalNumberOfCells() - 1);
                if (sb.length() > 0) {
                    resultCell.setCellValue(sb.toString());
                    validateOk = false;
                } else {
                    validateOk = true;
                    resultCell.setCellValue("Ok");
                }
                sb = new StringBuilder();
            }
            //</editor-fold>

            //<editor-fold desc="Insert dữ liệu nếu validate Ok" defaultstate="collapsed">
            if (validateOk) {
                for (int i = 0; i < rawDataList.size(); i++) {
                    Customer c = new Customer();
                    c.setName(rawDataList.get(i)[1].toString());
                    c.setSiteId(userSession.getSiteId());
                    c.setCode(null);
                    c.setDescription(rawDataList.get(i)[8].toString());
                    c.setCompanyName(rawDataList.get(i)[7].toString());
                    c.setCustomerImg(null);
                    c.setCreateDate(new Date());
                    c.setUpdateDate(null);
                    c.setStatus(1L);
                    c.setCreateBy(userSession.getUserName());
                    c.setUpdateBy(null);
                    c.setGender((short) 1);
                    c.setCurrentAddress(rawDataList.get(i)[5].toString());
//                    c.setPlaceOfBirth();
//                    c.setDateOfBirth();
                    c.setMobileNumber(null);
                    c.setEmail(null);
                    c.setUserName(null);
                    c.setAreaCode(null);
                    switch (rawDataList.get(i)[6].toString()) {
                        case "VIP":
                            c.setCustomerType(2L);
                            break;
                        case "Blacklist":
                            c.setCustomerType(3L);
                            break;
                        default:
                            c.setCustomerType(1L);
                            break;
                    }
                    if (rawDataList.get(i)[9].toString().equals(BundleUtils.getLangString("customer.yes", locale))) {
                        c.setCallAllowed(1L);
                    } else {
                        c.setCallAllowed(0L);
                    }
                    if (rawDataList.get(i)[10].toString().equals(BundleUtils.getLangString("customer.yes", locale))) {
                        c.setEmailAllowed(1L);
                    } else {
                        c.setEmailAllowed(0L);
                    }
                    if (rawDataList.get(i)[11].toString().equals(BundleUtils.getLangString("customer.yes", locale))) {
                        c.setSmsAllowed(1L);
                    } else {
                        c.setSmsAllowed(0L);
                    }
                    c.setIpccStatus("active");
                    Customer saved = customerRepository.save(c);
                    if (rawDataList.get(i).length > 2 && rawDataList.get(i)[2] != null) {
                        String[] mainPhone = rawDataList.get(i)[2].toString().split(";");
                        for (int j = 0; j < mainPhone.length; j++) {
                            CustomerContact cc = new CustomerContact();
                            cc.setCustomerId(saved.getCustomerId());
                            cc.setSiteId(userSession.getSiteId());
                            cc.setContactType((short) 5);
                            cc.setContact(mainPhone[j]);
                            cc.setIsDirectLine((short) 1);
                            cc.setStatus((short) 1);
                            cc.setCreateDate(new Date());
                            cc.setUpdateDate(new Date());
                            cc.setCreateBy(userSession.getUserName());
                            cc.setUpdateBy(userSession.getUserName());
                            customerContactRepository.save(cc);
                        }
                    }
                    if (rawDataList.get(i).length > 3 && rawDataList.get(i)[3] != null) {
                        String[] subPhone = rawDataList.get(i)[3].toString().split(";");
                        for (int j = 0; j < subPhone.length; j++) {
                            CustomerContact cc = new CustomerContact();
                            cc.setCustomerId(saved.getCustomerId());
                            cc.setSiteId(userSession.getSiteId());
                            cc.setContactType((short) 5);
                            cc.setContact(subPhone[j]);
                            cc.setIsDirectLine((short) 0);
                            cc.setStatus((short) 1);
                            cc.setCreateDate(new Date());
                            cc.setUpdateDate(new Date());
                            cc.setCreateBy(userSession.getUserName());
                            cc.setUpdateBy(userSession.getUserName());
                            customerContactRepository.save(cc);
                        }
                    }
                    if (rawDataList.get(i).length > 4 && rawDataList.get(i)[4] != null) {
                        String[] email = rawDataList.get(i)[4].toString().split(";");
                        for (int j = 0; j < email.length; j++) {
                            CustomerContact cc = new CustomerContact();
                            cc.setCustomerId(saved.getCustomerId());
                            cc.setSiteId(userSession.getSiteId());
                            cc.setContactType((short) 2);
                            cc.setContact(email[j]);
                            cc.setIsDirectLine((short) 1);
                            cc.setStatus((short) 1);
                            cc.setCreateDate(new Date());
                            cc.setUpdateDate(new Date());
                            cc.setCreateBy(userSession.getUserName());
                            cc.setUpdateBy(userSession.getUserName());
                            customerContactRepository.save(cc);
                        }
                    }
                    CustomizeFieldObject cfo = new CustomizeFieldObject();
                    cfo.setObjectId(saved.getCustomerId());
                    for (int j = 0; j < dynamicHeader.size(); j++) {
                        cfo.setCustomizeFieldId(dynamicHeader.get(j).getCustomizeFieldId());
                        if (rawDataList.get(i).length > (12 + j) && rawDataList.get(i)[12 + j] != null) {
                            switch (dynamicHeader.get(j).getType()) {
                                case "combobox":
                                    CustomizeFieldOptionValue cfov =
                                            customizeFieldOptionValueRepository.findCustomizeFieldOptionValueByNameEqualsAndStatus(rawDataList.get(i)[12 + j].toString(), 1L);
                                    cfo.setFieldOptionValueId(cfov.getFieldOptionValueId());
                                    break;
                                case "checkbox":
                                    if (rawDataList.get(i)[12 + j].toString().equals(BundleUtils.getLangString("customer.yes", locale))) {
                                        cfo.setValueCheckbox(1L);
                                    } else {
                                        cfo.setValueCheckbox(0L);
                                    }
                                    break;
                                case "date":
                                    Date date = dateFormat.parse(rawDataList.get(i)[12 + j].toString());
                                    cfo.setValueDate(date);
                                    break;
                                case "number":
                                    cfo.setValueNumber((Long) rawDataList.get(i)[12 + j]);
                                    break;
                                default:
                                    cfo.setValueText(rawDataList.get(i)[12 + j].toString());
                                    break;
                            }
                        }
                        cfo.setCreateBy(userSession.getUserName());
                        cfo.setCreateDate(new Date());
                        cfo.setStatus(1L);
                        cfo.setFunctionCode("CUSTOMER");
                        cfo.setTitle(dynamicHeader.get(j).getTitle());
                        customizeFieldObjectRepository.save(cfo);
                    }
                    CustomerListMapping clm = new CustomerListMapping();
                    clm.setCustomerId(saved.getCustomerId());
                    clm.setCompanySiteId(userSession.getCompanySiteId());
                    clm.setCustomerListId(customerListId);
                    customerListMappingRepository.save(clm);
                }
                FileOutputStream fos = new FileOutputStream(file);
                workbook.write(fos);
                result.put("file", file);
                result.put("message", BundleUtils.getLangString("customer.importSuccess", locale));
            } else {
                FileOutputStream fos = new FileOutputStream(file);
                workbook.write(fos);
                result.put("file", file);
                result.put("message", BundleUtils.getLangString("customer.importFailed", locale));
            }
            //</editor-fold>

            return result;
        } catch (Exception e) {
            LOGGER.info(e.getMessage());
            result.put("message", BundleUtils.getLangString("customer.errorValidate", locale));
            return result;
        }
    }

    //<editor-fold desc="Validate Methods" defaultstate="collapsed">
    private String validatePhone(String str, Locale locale) {
        String result = "";
        String[] arr = str.split(";");
        if (str.length() > 50) {
            result = BundleUtils.getLangString("customer.phoneMax50", locale);
        }
        for (int i = 0; i < arr.length; i++) {
            CustomerContact cc = customerContactRepository.findCustomerContactByContactEquals(arr[i]);
            if (cc != null) {
                return result.concat(BundleUtils.getLangString("customer.phoneExists", locale));
            }
        }
        return result;
    }

    private String validateDuplicateEmail(String str, Locale locale) {
        String result = "";
        String[] arr = str.split(";");
        for (int i = 0; i < arr.length; i++) {
            CustomerContact cc = customerContactRepository.findCustomerContactByContactEquals(arr[i]);
            if (cc != null) {
                return result.concat(BundleUtils.getLangString("customer.emailExists", locale));
            }
        }
        return result;
    }

    private String validateUsingRegexp(String header, String data, String regexp, Locale locale) {
        if (data.matches(regexp)) {
            return header + " " + BundleUtils.getLangString("customer.notMatch", locale);
        } else return "";
    }

    private String validateLength(String header, String str, int length, Locale locale) {
        if (str.trim().length() > length) {
            return header + " " + BundleUtils.getLangString("customer.notGreaterThan", locale) + " " + length;
        }
        return "";
    }

    private String validateDynamicLength(String header, String str, Long min, Long max, Locale locale) {
        if (str.trim().length() < min || str.trim().length() > max) {
            return header + " " + BundleUtils.getLangString("customer.notGreaterThan", locale) + " " + max + " " + BundleUtils.getLangString("customer.notLessThan", locale) + " " + min;
        }
        return "";
    }

    private boolean validateEmail(String str) {
        String[] arr = str.split(";");
        String regexp = "^[\\w-_\\.+]*[\\w-_\\.]\\@([\\w]+\\.)+[\\w]+[\\w]$";
        for (int i = 0; i < arr.length; i++) {
            if (!arr[i].matches(regexp)) {
                return false;
            }
        }
        return true;
    }

    private boolean validateLetter(String str) {
        String regexp = "@\"^\\p{L}+$\"";
        return str.matches(regexp);
    }
    //</editor-fold>

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public byte[] buildTemplate(Long companySiteId) {
        LOGGER.info("-----------BUILD TEMPLATE-----------");
        Locale locale = new Locale("vi", "VN");
        try {
            XSSFWorkbook workbook = new XSSFWorkbook();
            CreationHelper creationHelper = workbook.getCreationHelper();
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            Sheet sheet = workbook.createSheet("IMPORT");

            //<editor-fold desc="Tạo array header" defaultstate="collapsed">
            List<CustomizeFields> header = new ArrayList<>();
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.no", locale)));
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.fullname", locale)));
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.mainPhone", locale)));
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.secondPhone", locale)));
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.email", locale)));
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.address", locale)));
            header.add(new CustomizeFields("combobox", BundleUtils.getLangString("customer.cusType", locale)));
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.companyName", locale)));
            header.add(new CustomizeFields("text", BundleUtils.getLangString("customer.description", locale)));
            header.add(new CustomizeFields("combobox", BundleUtils.getLangString("customer.callAllowed", locale)));
            header.add(new CustomizeFields("combobox", BundleUtils.getLangString("customer.emailAllowed", locale)));
            header.add(new CustomizeFields("combobox", BundleUtils.getLangString("customer.smsAllowed", locale)));

            List<CustomizeFields> dynamicHeader = getDynamicHeader(companySiteId);
            header.addAll(dynamicHeader);
            //</editor-fold>

            //<editor-fold desc="Tạo style và font" defaultstate="collapsed">
            Font headerFont = workbook.createFont();
            Font importantFont = workbook.createFont();
            importantFont.setColor(IndexedColors.RED.index);
            headerFont.setBold(true);
            CellStyle headerStyle = workbook.createCellStyle();
            CellStyle importantStyle = workbook.createCellStyle();
            importantStyle.setFont(importantFont);
            headerStyle.setAlignment(HorizontalAlignment.CENTER);
            headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            headerStyle.setFont(headerFont);
            //</editor-fold>

            //<editor-fold desc="Thêm combobox" defaultstate="collapsed">

            //<editor-fold desc="Cho những trường động" defaultstate="collapsed">
            DataValidationHelper dataValidationHelper = sheet.getDataValidationHelper();
            for (int i = 0; i < dynamicHeader.size(); i++) {
                if (dynamicHeader.get(i).getType().equals("combobox")) {
                    String[] constraint;
                    List<CustomizeFieldOptionValue> list =
                            customizeFieldOptionValueRepository.findCustomizeFieldOptionValuesByFieldOptionIdAndStatus(dynamicHeader.get(i).getFieldOptionsId(), 1L);
                    constraint = new String[list.size()];
                    for (int j = 0; j < list.size(); j++) {
                        constraint[j] = list.get(j).getName();
                    }
                    DataValidationConstraint comboboxConstraint = dataValidationHelper.createExplicitListConstraint(constraint);
                    CellRangeAddressList comboboxCellRange = new CellRangeAddressList(4, 9999, 12 + i, 12 + i);
                    DataValidation comboboxValidation = dataValidationHelper.createValidation(comboboxConstraint, comboboxCellRange);
                    comboboxValidation.setSuppressDropDownArrow(true);
                    comboboxValidation.setShowErrorBox(true);
                    sheet.addValidationData(comboboxValidation);
                } else if (dynamicHeader.get(i).getType().equals("checkbox")) {
                    DataValidationConstraint yesNoConstraint = dataValidationHelper.createExplicitListConstraint(new String[]{BundleUtils.getLangString("customer.yes", locale), BundleUtils.getLangString("customer.not", locale)});
                    CellRangeAddressList checkboxCellRange = new CellRangeAddressList(4, 9999, 12 + i, 12 + i);
                    DataValidation yesNoValidation = dataValidationHelper.createValidation(yesNoConstraint, checkboxCellRange);
                    yesNoValidation.setShowErrorBox(true);
                    yesNoValidation.setSuppressDropDownArrow(true);
                    sheet.addValidationData(yesNoValidation);
                }
            }
            //</editor-fold>

            //<editor-fold desc="Cho những trường tĩnh" defaultstate="collapsed">
            DataValidationConstraint cusTypeConstraint = dataValidationHelper.createExplicitListConstraint(new String[]{BundleUtils.getLangString("customer.cusType.normal", locale), BundleUtils.getLangString("customer.cusType.vip", locale), BundleUtils.getLangString("customer.cusType.blacklist", locale)});
            DataValidationConstraint isAllowConstraint = dataValidationHelper.createExplicitListConstraint(new String[]{BundleUtils.getLangString("customer.yes", locale), BundleUtils.getLangString("customer.not", locale)});
            CellRangeAddressList cusTypeCellRangeAddressList = new CellRangeAddressList(3, 9999, 6, 6);
            CellRangeAddressList callCellRangeAddressList = new CellRangeAddressList(3, 9999, 9, 9);
            CellRangeAddressList emailCellRangeAddressList = new CellRangeAddressList(3, 9999, 10, 10);
            CellRangeAddressList smsCellRangeAddressList = new CellRangeAddressList(3, 9999, 11, 11);
            DataValidation cusTypeValidation = dataValidationHelper.createValidation(cusTypeConstraint, cusTypeCellRangeAddressList);
            DataValidation callValidation = dataValidationHelper.createValidation(isAllowConstraint, callCellRangeAddressList);
            DataValidation emailValidation = dataValidationHelper.createValidation(isAllowConstraint, emailCellRangeAddressList);
            DataValidation smsValidation = dataValidationHelper.createValidation(isAllowConstraint, smsCellRangeAddressList);
            cusTypeValidation.setSuppressDropDownArrow(true);
            cusTypeValidation.setShowErrorBox(true);
            callValidation.setSuppressDropDownArrow(true);
            callValidation.setShowErrorBox(true);
            emailValidation.setSuppressDropDownArrow(true);
            emailValidation.setShowErrorBox(true);
            smsValidation.setSuppressDropDownArrow(true);
            smsValidation.setShowErrorBox(true);
            sheet.addValidationData(cusTypeValidation);
            sheet.addValidationData(callValidation);
            sheet.addValidationData(emailValidation);
            sheet.addValidationData(smsValidation);
            //</editor-fold>

            //</editor-fold>

            //<editor-fold desc="Ghi header" defaultstate="collapsed">
            Drawing drawing = sheet.createDrawingPatriarch();
            ClientAnchor anchor = creationHelper.createClientAnchor();
            Row row0 = sheet.createRow(0);
            Row row2 = sheet.createRow(2);
            Row row3 = sheet.createRow(3);
            Cell cell0 = row0.createCell(0);
            cell0.setCellStyle(headerStyle);
            cell0.setCellValue(BundleUtils.getLangString("customer.importCustomer", locale));
            Cell cell2 = row2.createCell(0);
            cell2.setCellStyle(importantStyle);
            cell2.setCellValue(BundleUtils.getLangString("customer.notice", locale));
            for (int i = 0; i < header.size(); i++) {
                Cell headerCell = row3.createCell(i);
                headerCell.setCellValue(header.get(i).getTitle().split("#")[0]);
                headerStyle.setBorderTop(BorderStyle.THIN);
                headerStyle.setBorderRight(BorderStyle.THIN);
                headerStyle.setBorderBottom(BorderStyle.THIN);
                headerStyle.setBorderLeft(BorderStyle.THIN);
                headerFont.setFontHeightInPoints((short) 11);
                headerCell.setCellStyle(headerStyle);
                if (i == 0) {
                    sheet.setColumnWidth(i, 2500);
                } else {
                    sheet.setColumnWidth(i, 6000);
                }
                anchor.setCol1(headerCell.getColumnIndex());
                anchor.setCol2(headerCell.getColumnIndex() + 2);
                anchor.setRow1(row3.getRowNum());
                anchor.setRow2(row3.getRowNum() + 4);
                if (header.get(i).getTitle().contains("#")) {
                    Comment comment = drawing.createCellComment(anchor);
                    RichTextString str = creationHelper.createRichTextString(header.get(i).getTitle().split("#")[1]);
                    comment.setString(str);
                    comment.setAuthor("APACHE POI");
                    headerCell.setCellComment(comment);
                }
            }
            //</editor-fold>

            sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, 13));
            sheet.addMergedRegion(new CellRangeAddress(2, 2, 0, 13));
            workbook.write(os);
            os.flush();
            os.close();
            workbook.close();
            return os.toByteArray();
        } catch (Exception e) {
            LOGGER.error(e.getMessage());
            return null;
        }
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public List<CustomizeFieldObject> getCustomizeField(Long customerId) {
        List<CustomizeFieldObject> customizeFieldDTOList;
        try {
            customizeFieldDTOList = customizeFieldObjectRepository.findCustomizeFieldObjectsByFunctionCodeEqualsAndObjectId("CUSTOMER", customerId);
        } catch (Exception e) {
            LOGGER.info(e.getMessage());
            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
    @Transactional(DataSourceQualify.CCMS_FULL)
    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(" )," +
                    "cusInCampaign as (" +
                    "select * from campaign_customer " +
                    "where campaign_id = :p_campaign_id " +
                    "and company_site_id = :p_company_site_id " +
                    "and customer_list_id is null " +
                    "and in_campaign_status = 1");
            sb.append(" ), datas as (");
            sb.append(" select c.customer_id customerId,");
            sb.append(" c.name,");
            sb.append(" cP.phone mobileNumber,");
            sb.append(" cE.email,");
            sb.append(" c.customer_type customerType,");
            sb.append(" c.company_name companyName,");
            sb.append(" c.current_address currentAddress,");
            sb.append(" c.description,");
            sb.append(" c.ipcc_status ipccStatus,");
            sb.append(" c.call_allowed customerDnc");
            sb.append(" from customer c");
            sb.append(" inner join cusInCampaign cc on c.customer_id = cc.customer_id");
            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());
            param.put("p_campaign_id", campaignCustomerDTO.getCampaignId());
            param.put("p_company_site_id", campaignCustomerDTO.getCompanySiteId());
            customerList = namedParameterJdbcTemplate.query(sb.toString(), param, new BeanPropertyRowMapper<>(CustomerDTO.class));
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            return null;
        }
        return customerList;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO deleteCustomerFromCampaign(CampaignCustomerDTO campaignCustomerDTO) {
        ResultDTO resultDTO = new ResultDTO();
        Long companySiteId = campaignCustomerDTO.getCompanySiteId();
        Long campaignId = campaignCustomerDTO.getCampaignId();
        String[] lstCusId = campaignCustomerDTO.getLstCustomerId().split(",");
        List<Short> lstStatus = campaignCustomerRepository.getStatus();
        try {
            for (String cusId : lstCusId) {
                CampaignCustomer entity = campaignCustomerRepository.findCampaignCustomerByCampaignIdAndCompanySiteIdAndCustomerId(campaignId, companySiteId, Long.parseLong(cusId));
                if (entity.getStatus() == 0) {
                    campaignCustomerRepository.delete(entity);
                } else if (lstStatus.contains(entity.getStatus())) {
                    entity.setInCampaignStatus((short) 0);
                    campaignCustomerRepository.save(entity);
                }
            }
            resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
            resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
        }
        return resultDTO;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO searchCampaignInformation(CampaignCustomerDTO campaignCustomerDTO) {
        ResultDTO resultDTO = new ResultDTO();
        List<CampaignInformationDTO> list = new ArrayList<>();
        Map<String, Object> params = new HashMap<>();
        try {
            StringBuilder sb = new StringBuilder();
            sb.append(" with status_customer as (\n" +
                    "select complete_value\n" +
                    "from campaign_complete_code\n" +
                    "where complete_value <> 4\n" +
                    " and is_finish <> 1\n" +
                    " and campaign_type = 1\n" +
                    " and company_site_id = :p_company_site_id\n" +
                    "),\n" +
                    "count_customer as (\n" +
                    "select  campaign_id campaignId,\n" +
                    "     sum(case\n" +
                    "             when customer_list_id is null then 1\n" +
                    "             else 0\n" +
                    "         end) totalIndividual,\n" +
                    "     sum(case\n" +
                    "             when customer_list_id is not null then 1\n" +
                    "             else 0\n" +
                    "         end) totalCusInList\n" +
                    "from campaign_customer\n" +
                    "group by campaign_id\n" +
                    ")\n" +
                    "select a.*, b.customer_number campaignCustomer\n" +
                    "from count_customer a\n" +
                    "left join campaign b on a.campaignId = b.campaign_id\n" +
                    "where a.campaignId = :p_campaign_id");
            params.put("p_campaign_id", campaignCustomerDTO.getCampaignId());
            params.put("p_company_site_id", campaignCustomerDTO.getCompanySiteId());
            list = namedParameterJdbcTemplate.query(sb.toString(), params, BeanPropertyRowMapper.newInstance(CampaignInformationDTO.class));
            if (list.size() > 0) {
                resultDTO.setData(list.get(0));
            } else {
                resultDTO.setData(null);
            }
            resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
            resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
        }
        return resultDTO;
    }

    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO addCustomerToCampaign(CampaignCustomerDTO campaignCustomerDTO) {
        ResultDTO resultDTO = new ResultDTO();
        Long companySiteId = campaignCustomerDTO.getCompanySiteId();
        Long campaignId = campaignCustomerDTO.getCampaignId();
        String[] lstCusId = campaignCustomerDTO.getLstCustomerId().split(",");
        try {
            for (String cusId: lstCusId) {
                CampaignCustomer entity = new CampaignCustomer();
                entity.setCompanySiteId(companySiteId);
                entity.setStatus((short) 0);
                entity.setCampaignId(campaignId);
                entity.setCustomerId(Long.parseLong(cusId));
                entity.setRecallCount(0L);
                entity.setInCampaignStatus((short) 1);
                campaignCustomerRepository.save(entity);
            }
            resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
            resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
        }
        return resultDTO;
    }


    @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;
    }

//        params.put('1', ["AND","AGE",">=","30"] )
//        lst.push(params);
//        StringBuilder sql = "Select ..... WHERE 1 = 1 "
//        for(lst){
//            String[] data = lst[i].value
//            sql.append(data[0] + data[1] + data[2] + data[3]);
//        }


//    Map<String, String> params = new HashMap<>();


    //    public ResultDTO searchCustomize(List<CustomizeFields> customizeFields) {
//        Map<String, CustomizeRequestDTo> hashCustomer = new HashMap<>();
//        CustomizeRequestDTo customizeRequestDTo = new CustomizeRequestDTo();
//        hashCustomer.put("1", customizeRequestDTo);
//        hashCustomer.put("2", customizeRequestDTo);
//        hashCustomer.put("3", customizeRequestDTo);
//        StringBuilder sb = new StringBuilder();
//        sb.append("");
//        sb.append("");
//        sb.append("");
//        sb.append("");
    @Override
    public ResultDTO listCustomizeFields(CustomizeFieldsDTO customizeFields) {
        ResultDTO resultDTO = new ResultDTO();
        Map<String, String> params = new HashMap<>();
        List<CustomizeFielObjectDTO> list;
        StringBuilder stringBuilder = new StringBuilder();
        try {
            List<CustomizeFields> lstCustomizeFields = customizeFieldsRepository.findByFunctionCodeAndActiveAndStatusAndSiteId(customizeFields.getFunctionCode(), customizeFields.getActive(), customizeFields.getStatus(), customizeFields.getSiteId());
            String cf[][] = {
                    {"-1", "Mã Khách Hàng", "number"},
                    {"-2", "Tên khách hàng", "text"},
                    {"-3", "Tên công ty", "text"},
                    {"-4", "Giới tính", "number"},
                    {"-5", "Địa chỉ", "text"},
                    {"-6", "Nơi sinh", "text"},
                    {"-7", "Ngày sinh", "date"},
                    {"-8", "Số điện thoại", "number"},
                    {"-9", "email", "text"},
                    {"-10", "Tên đăng nhập", "text"},
                    {"-11", "Loại Khách hàng", "number"},
            };
            for (int x = 0; x < 11; x++) {
                CustomizeFields datafill = new CustomizeFields();
                datafill.setCustomizeFieldId(Long.parseLong(cf[x][0]));
                datafill.setTitle(cf[x][1]);
                datafill.setType(cf[x][2]);
                lstCustomizeFields.add(datafill);
            }

//        try {
//            stringBuilder.append(" with column_name_temp as (");
//            stringBuilder.append("    select 'CUSTOMER_ID customerId'  , from user_tab_columns, dual");
//            stringBuilder.append(" union all");
//            stringBuilder.append("    select 'CUSTOMER_NAME customerName' , from user_tab_columns, dual");
//            stringBuilder.append(" union all");
//            stringBuilder.append("     select 'CUSTOMER_TYPE customerType'  , from user_tab_columns, dual");
//            stringBuilder.append(" union all");
//            stringBuilder.append("     select 'NAME name'   , from user_tab_columns, dual");
//            stringBuilder.append(" union all");
//            stringBuilder.append("     select 'CURRENT_ADDRESS currentAddress',  from user_tab_columns, dual");
//            stringBuilder.append(" union all");
//            stringBuilder.append("     select 'PLACE_OF_BIRTH placeOfBirth',  from user_tab_columns, dual");
//            stringBuilder.append(" union all");
//            stringBuilder.append("     select 'DATE_OF_BIRTH dateOfBirth',  from user_tab_columns, dual");
//            stringBuilder.append(" union all");
//            stringBuilder.append("     select 'MOBILE_NUMBER mobileNumber',  from user_tab_columns, dual");
//            stringBuilder.append(" union all");
//            stringBuilder.append("     select 'EMAIL email',  from user_tab_columns, dual");
//            stringBuilder.append(" union all");
//            stringBuilder.append("     select 'USERNAME username',  from user_tab_columns, dual");
//            stringBuilder.append(" union all");
//            stringBuilder.append("     select 'CUSTOMER_TYPE customerType',  from user_tab_columns, dual");
//            stringBuilder.append("     where table_name = 'CUSTOMER'");
//            stringBuilder.append(" )");
//
//            stringBuilder.append(" select * from column_name_temp");
//            stringBuilder.append(" union all");
//            stringBuilder.append(" select title columnName, 0 isFix ");
//            stringBuilder.append(" from customize_fields, dual");
//            stringBuilder.append(" where function_code = 'CUSTOMER'");
//            stringBuilder.append("     and site_id = :p_company_site_id");
//            stringBuilder.append("     and STATUS = 1");
//            stringBuilder.append("   and active = 1 ");
//            params.put("p_company_site_id", customizeFields.getSiteId());
//            params.put("p_customer_id", customizeFields.getCustomerId());
//            LOGGER.info("SQL statement: " + stringBuilder);
//            list = namedParameterJdbcTemplate.query(stringBuilder.toString(), params, BeanPropertyRowMapper.newInstance(CustomizeFielObjectDTO.class));
            resultDTO.setErrorCode(Constants.ApiErrorCode.SUCCESS);
            resultDTO.setDescription(Constants.ApiErrorDesc.SUCCESS);
            resultDTO.setListData(lstCustomizeFields);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            resultDTO.setErrorCode(Constants.ApiErrorCode.ERROR);
            resultDTO.setDescription(Constants.ApiErrorDesc.ERROR);
        }

        return resultDTO;
    }


    @Override
    @Transactional(DataSourceQualify.CCMS_FULL)
    public ResultDTO searchCustomizeFields(CampaignCustomerDTO campaignCustomerDTO) {
        ResultDTO resultDTO = new ResultDTO();
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

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

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

        try {


            StringBuilder sb = new StringBuilder();

            sb.append("select");
            sb.append("    C.NAME name,");
            sb.append("    C.CUSTOMER_ID customerID,");
            sb.append("    C.USERNAME username,");
            sb.append("    C.GENDER gender,");
            sb.append("    C.COMPANY_NAME companyName,");
            sb.append("    C.DATE_OF_BIRTH dateOfBirth,");
            sb.append("    C.CUSTOMER_TYPE customerType,");
            sb.append("    C.COMPANY_NAME companyName,");
            sb.append("     C.PLACE_OF_BIRTH placeOfBirth,");
            sb.append("    C.EMAIL email,");
            sb.append("    C.MOBILE_NUMBER mobileNumber,");
            sb.append("    C.STATUS status,");
            sb.append("    C.SITE_ID siteId,");
            sb.append("    CF.FUNCTION_CODE functionCode,");
            sb.append("    CF.ACTIVE active,");
            sb.append("    CFO.*");
            sb.append("    FROM CUSTOMER C");
            sb.append("  INNER JOIN CUSTOMIZE_FIELD_OBJECT CFO ON C.CUSTOMER_ID = CFO.OBJECT_ID");
            sb.append("   INNER JOIN CUSTOMIZE_FIELDS CF ON CF.CUSTOMIZE_FIELD_ID = CFO.CUSTOMIZE_FIELDS_ID\n" +
                    "   WHERE 1 = 1");
            sb.append("     and CFO.STATUS = 1");
            sb.append("   and active = 1 ");
            sb.append("  and  CF.FUNCTION_CODE = 'CUSTOMER' ");

            for (int i = 0; i < campaignCustomerDTO.getListQuery().size(); i++) {

                sb.append( campaignCustomerDTO.getListQuery().get(i).getJoin() + " "
                        +  campaignCustomerDTO.getListQuery().get(i).getField() + " "
                        +  campaignCustomerDTO.getListQuery().get(i).getOperator() + " "
                        +  campaignCustomerDTO.getListQuery().get(i).getCondition());
            }

            SQLQuery query = session.createSQLQuery(sb.toString());
            query.addScalar("customerId", new LongType());
            query.addScalar("name", new StringType());
            query.addScalar("userName", new StringType());
            query.addScalar("companyName", new StringType());
            query.addScalar("customerType", new LongType());
            query.addScalar("currentAddress", new StringType());
            query.addScalar("mobileNumber", new StringType());
            query.addScalar("email", new StringType());
            query.addScalar("placeOfBirth",new StringType());
            query.addScalar("dateOfBirth", new DateType());
            query.addScalar("status", new ShortType());
            query.addScalar("siteId",new LongType());
            query.addScalar("active",new StringType());


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

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

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

        return resultDTO;

    }


}
