package com.viettel.campaign.service.impl;

import com.viettel.campaign.mapper.CustomerListMapper;
import com.viettel.campaign.model.CustomerContact;
import com.viettel.campaign.model.CustomerList;
import com.viettel.campaign.repository.*;
import com.viettel.campaign.service.CustomerService;
import com.viettel.campaign.utils.Constants;
import com.viettel.campaign.utils.HibernateUtil;
import com.viettel.campaign.utils.SQLBuilder;
import com.viettel.campaign.web.dto.CustomerCustomDTO;
import com.viettel.campaign.web.dto.CustomerDTO;
import com.viettel.campaign.web.dto.CustomerListDTO;
import com.viettel.campaign.web.dto.ResultDTO;
import com.viettel.campaign.mapper.CustomerMapper;
import com.viettel.campaign.model.Customer;
import com.viettel.campaign.utils.DataUtil;
import com.viettel.campaign.web.dto.request_dto.SearchCustomerRequestDTO;
import com.viettel.campaign.web.dto.request_dto.CustomerRequestDTO;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.transform.Transformers;
import org.hibernate.type.DateType;
import org.hibernate.type.LongType;
import org.hibernate.type.ShortType;
import org.hibernate.type.StringType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.*;

@Service
public class CustomerServiceImpl implements CustomerService {

    @Autowired
    EntityManager entityManager;

    @Autowired
    CustomerRepository customerRepository;

    @Autowired
    CustomerListRepository customerListRepository;

    @Autowired
    CustomerContactRepository customerContactRepository;

    @Autowired
    CampaignCustomerListRepository campaignCustomerListRepository;

    @Autowired
    CustomerListMappingRepository customerListMappingRepository;

    @Override
    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 name DESC");

            SQLQuery query = session.createSQLQuery(sqlStrBuilder.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("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
    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
    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"));

            sqlStrBuilder.append(" AND ");
            sqlStrBuilder.append(" ORDER BY name DESC");
            sqlStrBuilder.append(" ORDER BY name DESC");
            sqlStrBuilder.append(" ORDER BY name DESC");

            SQLQuery query = session.createSQLQuery(sqlStrBuilder.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("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
    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;
    }

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

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

    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
    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 sqlStrBuilder = new StringBuilder();
            sqlStrBuilder.append(SQLBuilder.getSqlQueryById(SQLBuilder.SQL_MODULE_CAMPAIGN_MNG, "search-campaign-customer-by-params"));

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

            SQLQuery query = session.createSQLQuery(sqlStrBuilder.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
    public ResultDTO createCustomerList(CustomerListDTO customerListDTO) {
        ResultDTO resultDTO = new ResultDTO();
        CustomerListMapper customerListMapper = new CustomerListMapper();
        CustomerList customerList = new CustomerList();
        try {
            if (customerListDTO != null) {
                // insert
                CustomerList findCustomer = customerListRepository.findByCustomerListCode(customerListDTO.getCustomerListCode());
                if (findCustomer == null) {
                    customerList = customerListMapper.toPersistenceBean(customerListDTO);
                    customerListRepository.save(customerList);

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

        return resultDTO;
    }

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

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

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

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

        return resultDTO;
    }

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

    @Transactional
    @Override
    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
    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 sqlStrBuilder = new StringBuilder();
            sqlStrBuilder.append(SQLBuilder.getSqlQueryById(SQLBuilder.SQL_MODULE_CAMPAIGN_MNG, "search-campaign-customer-by-params"));

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

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

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

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

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

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

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

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

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

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

        return resultDTO;
    }

    @Override
    public ResultDTO getCustomerContact(Long customerId, Short contactType, String contact) {
        ResultDTO result = new ResultDTO();

        List<CustomerContact> customer = customerContactRepository.findByCustomerIdAndAndContactTypeAndContact(customerId, contactType, contact);

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

        return result;
    }
}
