package com.viettel.campaign.repository.impl;

import com.viettel.campaign.repository.CampaignRepositoryCustom;
import com.viettel.campaign.utils.Constants;
import com.viettel.campaign.utils.DataUtil;
import com.viettel.campaign.utils.HibernateUtil;
import com.viettel.campaign.utils.SQLBuilder;
import com.viettel.campaign.web.dto.CampaignDTO;
import com.viettel.campaign.web.dto.ResultDTO;
import com.viettel.campaign.web.dto.request_dto.CampaignRequestDTO;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.transform.Transformers;
import org.hibernate.type.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Repository;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Repository
public class CampaignRepositoryImpl implements CampaignRepositoryCustom {

    @Autowired
    EntityManager entityManager;

    @Override
    public ResultDTO searchCampaignExecute(CampaignRequestDTO campaignRequestDto) {
        ResultDTO result = new ResultDTO();
        List<CampaignDTO> lst = new ArrayList<>();
        StringBuilder expression = new StringBuilder()
                .append(" SELECT C.CAMPAIGN_CODE, C.CAMPAIGN_NAME, C.CONTENT, C.START_TIME, C.END_TIME, C.STATUS ")
                .append(" FROM CAMPAIGN C INNER JOIN CAMPAIGN_AGENT CA ON C.CAMPAIGN_ID = CA.CAMPAIGN_ID ")
                .append(" WHERE 1 = 1 ")
                //.append(" AND CA.AGENT_ID = :pAgentId ")
                .append(" AND C.STATUS IN (2,3) ");

        if (!DataUtil.isNullOrEmpty(campaignRequestDto.getCampaignCode())) {
            expression.append(" AND C.CAMPAIGN_ID IN (:pCampaingId) ");
        }

        if (!DataUtil.isNullOrEmpty(campaignRequestDto.getCampaignName())) {
            expression.append(" AND UPPER(C.CAMPAIGN_NAME) LIKE CONCAT('%',:pCampaignName,'%') ");
        }

        if (!DataUtil.isNullOrZero(campaignRequestDto.getStatus().longValue())) {
            if (campaignRequestDto.getStatus() != 0)
                expression.append(" AND C.STATUS = :pStatus ");
            else
                expression.append(" AND C.STATUS IN (1, 2, 3) ");
        }

        if (!DataUtil.isNullOrEmpty(campaignRequestDto.getFromDateFr())) {
            expression.append(" AND TRUNC(C.START_TIME) >= TRUNC(:pStartTimeFr) ");
        }

        if (!DataUtil.isNullOrEmpty(campaignRequestDto.getFromDateTo())) {
            expression.append(" AND TRUNC(C.START_TIME) <= TRUNC(:pStartTimeTo) ");
        }

        if (!DataUtil.isNullOrEmpty(campaignRequestDto.getToDateFr())) {
            expression.append(" AND TRUNC(C.END_TIME) >= TRUNC(:pEndTimeFr) ");
        }

        if (!DataUtil.isNullOrEmpty(campaignRequestDto.getToDateTo())) {
            expression.append(" AND TRUNC(C.END_TIME) <= TRUNC(:pEndTimeTo) ");
        }

        if (!DataUtil.isNullOrZero(campaignRequestDto.getNumOfCusFr())) {
            expression.append(" AND C.CUSTOMER_NUMBER >= :pCustNumFr ");
        }

        if (!DataUtil.isNullOrZero(campaignRequestDto.getNumOfCusTo())) {
            expression.append(" AND C.CUSTOMER_NUMBER <= :pCustNumTo ");
        }

        try {
            Query query = entityManager.createNativeQuery(expression.toString());
            //query.setParameter("pAgentId", campaignRequestDto.getAgentId());

            if (!DataUtil.isNullOrEmpty(campaignRequestDto.getCampaignCode())) {
                String[] lstCode = campaignRequestDto.getCampaignCode().split(",");
                query.setParameter(":pCampaingId", lstCode);
            }

            if (!DataUtil.isNullOrEmpty(campaignRequestDto.getCampaignName())) {
                query.setParameter(":pCampaignName", campaignRequestDto.getCampaignName().toUpperCase());
            }

            if (!DataUtil.isNullOrZero(campaignRequestDto.getStatus().longValue())) {
                if (campaignRequestDto.getStatus() != 0)
                    query.setParameter(":pStatus", campaignRequestDto.getStatus());
            }

            if (!DataUtil.isNullOrEmpty(campaignRequestDto.getFromDateFr())) {
                query.setParameter(":pStartTimeFr", campaignRequestDto.getFromDateFr());
            }

            if (!DataUtil.isNullOrEmpty(campaignRequestDto.getFromDateTo())) {
                query.setParameter(":pStartTimeTo", campaignRequestDto.getFromDateTo());
            }

            if (!DataUtil.isNullOrEmpty(campaignRequestDto.getToDateFr())) {
                query.setParameter(":pEndTimeFr", campaignRequestDto.getToDateFr());
            }

            if (!DataUtil.isNullOrEmpty(campaignRequestDto.getToDateTo())) {
                query.setParameter(":pEndTimeTo", campaignRequestDto.getToDateTo());
            }

            if (!DataUtil.isNullOrZero(campaignRequestDto.getNumOfCusFr())) {
                query.setParameter(":pCustNumFr", campaignRequestDto.getNumOfCusFr());
            }

            if (!DataUtil.isNullOrZero(campaignRequestDto.getNumOfCusTo())) {
                query.setParameter(":pCustNumTo", campaignRequestDto.getNumOfCusTo());
            }

            result.setTotalRow(query.getResultList().size());

            Pageable pageable = SQLBuilder.buildPageable(campaignRequestDto);
            if (pageable != null) {
                query.setFirstResult(pageable.getPageNumber() * pageable.getPageSize());
                query.setMaxResults(pageable.getPageSize());
            }

            List<Object[]> data = query.getResultList();

            for (Object[] obj : data) {
                CampaignDTO item = new CampaignDTO();
                item.setPage(campaignRequestDto.getPage());
                item.setPageSize(campaignRequestDto.getPageSize());
                item.setSort(campaignRequestDto.getSort());
                item.setCampaignCode((String) obj[0]);
                item.setCampaignName((String) obj[1]);
                item.setContent((String) obj[2]);
                item.setStartTime((Date) obj[3]);
                item.setEndTime((Date) obj[4]);
                item.setStatus(((BigDecimal) obj[5]).shortValueExact());

                lst.add(item);
            }

            result.setErrorCode(Constants.ApiErrorCode.SUCCESS);
            result.setDescription(Constants.ApiErrorDesc.SUCCESS);
            result.setListData(lst);

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

        return result;
    }

    @Override
    public ResultDTO search(CampaignRequestDTO requestDto) {
        ResultDTO result = new ResultDTO();
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

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

        if (DataUtil.isNullOrEmpty(requestDto.getCompanySiteId())) {
            result.setErrorCode(Constants.ApiErrorCode.ERROR);
            result.setDescription(Constants.ApiErrorDesc.ERROR);
            return result;
        }
        try {
            StringBuilder sqlStr = new StringBuilder();
            sqlStr.append(SQLBuilder.getSqlQueryById(SQLBuilder.SQL_MODULE_CAMPAIGN_MNG, "search-campaign-by-params"));
            if (!DataUtil.isNullOrEmpty(requestDto.getCampaignCode())) {
                sqlStr.append(" AND a.CAMPAIGN_CODE IN (:p_code) ");
            }
            if (!DataUtil.isNullOrEmpty(requestDto.getCampaignName())) {
                sqlStr.append(" AND UPPER(a.CAMPAIGN_NAME) LIKE :p_name");
            }
            if (requestDto.getStatus() != null && requestDto.getStatus() > 0) {
                sqlStr.append(" AND a.STATUS = :p_status");
            }
            if (!DataUtil.isNullOrEmpty(requestDto.getFromDateFr())) {
                sqlStr.append(" AND TO_DATE(a.START_TIME, 'DD/MM/YYYY') >= :p_frDateFr");
            }
            if (!DataUtil.isNullOrEmpty(requestDto.getToDateFr())) {
                sqlStr.append(" AND TO_DATE(a.START_TIME, 'DD/MM/YYYY') <= :p_toDateFr");
            }
            if (!DataUtil.isNullOrEmpty(requestDto.getFromDateTo())) {
                sqlStr.append(" AND TO_DATE(a.END_TIME, 'DD/MM/YYYY') >= :p_frDateTo");
            }
            if (!DataUtil.isNullOrEmpty(requestDto.getToDateTo())) {
                sqlStr.append(" AND TO_DATE(a.END_TIME, 'DD/MM/YYYY') <= :p_toDateTo");
            }
            if (!DataUtil.isNullOrZero(requestDto.getNumOfCusFr())) {
                sqlStr.append(" AND a.CUSTOMER_NUMBER >= :p_cusNumFr");
            }
            if (!DataUtil.isNullOrZero(requestDto.getNumOfCusTo())) {
                sqlStr.append(" AND a.CUSTOMER_NUMBER <= :p_cusNumTo");
            }
            if (requestDto.getType() != null) {
                sqlStr.append(" AND a.CAMPAIGN_TYPE = :p_type");
            }
            if (requestDto.getChanel() != null && requestDto.getChanel() > 0) {
                sqlStr.append(" AND a.CHANEL = :p_chanel");
            }
            if (!DataUtil.isNullOrZero(requestDto.getNumOfCusFr())) {
                sqlStr.append(" AND a.CUSTOMER_NUMBER >= :p_cusNumFr");
            }
            if (!DataUtil.isNullOrZero(requestDto.getNumOfCusTo())) {
                sqlStr.append(" AND a.CUSTOMER_NUMBER <= :p_cusNumTo");
            }

            sqlStr.append(" ORDER BY a.START_TIME DESC ");

            SQLQuery query = session.createSQLQuery(sqlStr.toString());
            if (!DataUtil.isNullOrEmpty(requestDto.getCampaignCode())) {
                String[] lstCode = requestDto.getCampaignCode().split(",");
                query.setParameterList("p_code", lstCode);
            }

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

            query.setParameter("p_company_site_id", requestDto.getCompanySiteId());

            if (requestDto.getStatus() != null && requestDto.getStatus() > 0) {
                query.setParameter("p_status", requestDto.getStatus());
            }
            if (!DataUtil.isNullOrEmpty(requestDto.getFromDateFr())) {
                query.setParameter("p_frDateFr", requestDto.getFromDateFr());
            }
            if (!DataUtil.isNullOrEmpty(requestDto.getFromDateTo())) {
                query.setParameter("p_frDateTo", requestDto.getFromDateTo());
            }
            if (!DataUtil.isNullOrEmpty(requestDto.getToDateFr())) {
                query.setParameter("p_toDateFr", requestDto.getToDateFr());
            }
            if (!DataUtil.isNullOrEmpty(requestDto.getToDateTo())) {
                query.setParameter("p_toDateTo", requestDto.getToDateTo());
            }
            if (requestDto.getType() != null) {
                query.setParameter("p_type", requestDto.getType());
            }
            if (requestDto.getChanel() != null && requestDto.getChanel() > 0) {
                query.setParameter("p_chanel", requestDto.getChanel());
            }
            if (!DataUtil.isNullOrZero(requestDto.getNumOfCusFr())) {
                query.setParameter("p_cusNumFr", requestDto.getNumOfCusFr() == 0 ? null : requestDto.getNumOfCusFr());
            }
            if (!DataUtil.isNullOrZero(requestDto.getNumOfCusTo())) {
                query.setParameter("p_cusNumTo", requestDto.getNumOfCusTo() == 0 ? null : requestDto.getNumOfCusTo());
            }

            query.addScalar("campaignId", new BigDecimalType());
            query.addScalar("campaignCode", new StringType());
            query.addScalar("campaignName", new StringType());
            query.addScalar("campaignType", new StringType());
            query.addScalar("chanel", new ShortType());
            query.addScalar("startTime", new DateType());
            query.addScalar("endTime", new DateType());
            query.addScalar("customerNumber", new BigDecimalType());
            query.addScalar("status", new ShortType());
            query.addScalar("numOfJoinedCus", new LongType());
            query.addScalar("numOfNotJoinedCus", new LongType());
            query.addScalar("numOfLockCus", new LongType());

            query.setResultTransformer(Transformers.aliasToBean(CampaignDTO.class));
            int count = 0;
            List<CampaignDTO> list = query.list();
            if (list.size() > 0) {
                count = query.list().size();
            }
            Pageable pageable = SQLBuilder.buildPageable(requestDto);
            if (pageable != null) {
                query.setFirstResult(pageable.getPageNumber() * pageable.getPageSize());
                query.setMaxResults(pageable.getPageSize());
            }
            List<CampaignDTO> data = query.list();
            Page<CampaignDTO> dataPage = new PageImpl<>(data, pageable, count);
            result.setData(dataPage);
            result.setErrorCode(Constants.ApiErrorCode.SUCCESS);
            result.setDescription(Constants.ApiErrorDesc.SUCCESS);
            session.close();
            return result;
        } catch (Exception ex) {
            session.close();
        }
        result.setErrorCode(Constants.ApiErrorCode.ERROR);
        result.setDescription(Constants.ApiErrorDesc.ERROR);
        return result;
    }

    @Override
    public ResultDTO findByCampaignCode(CampaignRequestDTO requestDto) {
        ResultDTO result = new ResultDTO();
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

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

        if (DataUtil.isNullOrEmpty(requestDto.getCompanySiteId())) {
            result.setErrorCode(Constants.ApiErrorCode.ERROR);
            result.setDescription(Constants.ApiErrorDesc.ERROR);
            return result;
        }
        try {
            StringBuilder sqlStr = new StringBuilder();
            sqlStr.append(" SELECT CAMPAIGN_ID campaignId, " +
                    "       CAMPAIGN_CODE campaignCode, " +
                    "       CAMPAIGN_NAME campaignName, " +
                    "       START_TIME startTime," +
                    "       END_TIME endTime, " +
                    "       STATUS status " +
                    " FROM CAMPAIGN" +
                    " WHERE COMPANY_SITE_ID = :p_company_site_id AND STATUS <> -1 ");
            if (!DataUtil.isNullOrEmpty(requestDto.getCampaignCode())) {
                sqlStr.append(" AND CAMPAIGN_CODE LIKE :p_code ");
            }
            sqlStr.append(" ORDER BY START_TIME DESC ");
            SQLQuery query = session.createSQLQuery(sqlStr.toString());
            query.setParameter("p_company_site_id", requestDto.getCompanySiteId());
            if (!DataUtil.isNullOrEmpty(requestDto.getCampaignCode())) {
                query.setParameter("p_code", "%" +
                        requestDto.getCampaignCode().toUpperCase()
                                .replace("\\", "\\\\")
                                .replaceAll("%", "\\\\%")
                                .replaceAll("_", "\\\\_")
                        + "%");
            }
            query.addScalar("campaignId", new BigDecimalType());
            query.addScalar("campaignCode", new StringType());
            query.addScalar("campaignName", new StringType());
            query.addScalar("startTime", new DateType());
            query.addScalar("endTime", new DateType());
            query.addScalar("status", new ShortType());

            query.setResultTransformer(Transformers.aliasToBean(CampaignDTO.class));
            int count = 0;
            List<CampaignDTO> list = query.list();
            if (list.size() > 0) {
                count = query.list().size();
            }
            Pageable pageable = SQLBuilder.buildPageable(requestDto);
            if (pageable != null) {
                query.setFirstResult(pageable.getPageNumber() * pageable.getPageSize());
                query.setMaxResults(pageable.getPageSize());
            }
            List<CampaignDTO> data = query.list();
            Page<CampaignDTO> dataPage = new PageImpl<>(data, pageable, count);
            result.setData(dataPage);
            result.setErrorCode(Constants.ApiErrorCode.SUCCESS);
            result.setDescription(Constants.ApiErrorDesc.SUCCESS);
            session.close();

            return result;
        } catch (Exception ex) {
            session.close();
        }
        result.setErrorCode(Constants.ApiErrorCode.ERROR);
        result.setDescription(Constants.ApiErrorDesc.ERROR);
        return result;
    }

}
