package vn.azteam.tpf.service;

import java.time.Instant;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.criteria.JoinType;

import io.github.jhipster.service.filter.LongFilter;
import io.github.jhipster.service.filter.StringFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import io.github.jhipster.service.QueryService;

import org.springframework.web.multipart.MultipartFile;
import vn.azteam.tpf.Constants.Constants;
import vn.azteam.tpf.domain.TBEnvironmentUpdate;
import vn.azteam.tpf.domain.*; // for static metamodels
import vn.azteam.tpf.repository.TBEnvironmentUpdateRepository;
import vn.azteam.tpf.service.dto.*;
import vn.azteam.tpf.service.mapper.TBEnvironmentUpdateMapper;
import vn.azteam.tpf.service.mapper.TBGuidelineDetailsMapper;
import vn.azteam.tpf.service.mapper.TBLimitsMapper;

/**
 * Service for executing complex queries for TBEnvironmentUpdate entities in the database.
 * The main input is a {@link TBEnvironmentUpdateCriteria} which gets converted to {@link Specification},
 * in a way that all the filters must apply.
 * It returns a {@link List} of {@link TBEnvironmentUpdateDTO} or a {@link Page} of {@link TBEnvironmentUpdateDTO} which fulfills the criteria.
 */
@Service
@Transactional(readOnly = true)
public class TBEnvironmentUpdateQueryService extends QueryService<TBEnvironmentUpdate> {

    private final Logger log = LoggerFactory.getLogger(TBEnvironmentUpdateQueryService.class);

    private final TBEnvironmentUpdateService tBEnvironmentUpdateService;

    private final TBEnvironmentUpdateRepository tBEnvironmentUpdateRepository;

    private final TBEnvironmentUpdateMapper tBEnvironmentUpdateMapper;

    private final TBActivityService tBActivityService;

    private final TBCropQueryService tBCropQueryService;

    private final TBCropService tBCropService;

    private final UserService userService;

    private final TBActivityTypeQueryService tBActivityTypeQueryService;

    private final TBActivityQueryService tBActivityQueryService;

    private final TBEnvironmentalParameterQueryService tBEnvironmentalParameterQueryService;

    private final TBEnvironmentalParameterService tBEnvironmentalParameterService;

    private final TBEntityService tBEntityService;

    private final PushNotificationService pushNotificationService;

    private final EntityManager entityManager;

    private final TBGuidelineDetailsMapper tbGuidelineDetailsMapper;

    private final TBLimitsMapper tbLimitsMapper;

    private final TBCropTypeService tbCropTypeService;

    @Value("${app.is-test-send-notification}")
    private Integer isTestSendNotification;

    public TBEnvironmentUpdateQueryService(TBEnvironmentUpdateService tBEnvironmentUpdateService,
                                           TBEnvironmentUpdateRepository tBEnvironmentUpdateRepository,
                                           TBEnvironmentUpdateMapper tBEnvironmentUpdateMapper,
                                           TBActivityService tBActivityService,
                                           TBCropQueryService tBCropQueryService,
                                           TBCropService tBCropService, UserService userService,
                                           TBActivityTypeQueryService tBActivityTypeQueryService,
                                           TBEnvironmentalParameterQueryService tBEnvironmentalParameterQueryService,
                                           TBActivityQueryService tBActivityQueryService,
                                           TBEnvironmentalParameterService tBEnvironmentalParameterService,
                                           TBEntityService tBEntityService,
                                           PushNotificationService pushNotificationService,
                                           EntityManager entityManager, TBGuidelineDetailsMapper tbGuidelineDetailsMapper, TBLimitsMapper tbLimitsMapper, TBCropTypeService tbCropTypeService) {
        this.tBEnvironmentUpdateRepository = tBEnvironmentUpdateRepository;
        this.tBEnvironmentUpdateMapper = tBEnvironmentUpdateMapper;
        this.tBActivityService = tBActivityService;
        this.tBCropQueryService = tBCropQueryService;
        this.tBCropService = tBCropService;
        this.userService = userService;
        this.tBActivityTypeQueryService = tBActivityTypeQueryService;
        this.tBEnvironmentalParameterQueryService = tBEnvironmentalParameterQueryService;
        this.tBActivityQueryService = tBActivityQueryService;
        this.tBEnvironmentalParameterService = tBEnvironmentalParameterService;
        this.tBEnvironmentUpdateService = tBEnvironmentUpdateService;
        this.tBEntityService = tBEntityService;
        this.pushNotificationService = pushNotificationService;
        this.entityManager = entityManager;
        this.tbGuidelineDetailsMapper = tbGuidelineDetailsMapper;
        this.tbLimitsMapper = tbLimitsMapper;
        this.tbCropTypeService = tbCropTypeService;
    }

    /**
     * Return a {@link List} of {@link TBEnvironmentUpdateDTO} which matches the criteria from the database
     *
     * @param criteria The object which holds all the filters, which the entities should match.
     * @return the matching entities.
     */
    @Transactional(readOnly = true)
    public List<TBEnvironmentUpdateDTO> findByCriteria(TBEnvironmentUpdateCriteria criteria) {
        log.debug("find by criteria : {}", criteria);
        final Specification<TBEnvironmentUpdate> specification = createSpecification(criteria);
        return tBEnvironmentUpdateMapper.toDto(tBEnvironmentUpdateRepository.findAll(specification));
    }

    /**
     * Return a {@link Page} of {@link TBEnvironmentUpdateDTO} which matches the criteria from the database
     *
     * @param criteria The object which holds all the filters, which the entities should match.
     * @param page     The page, which should be returned.
     * @return the matching entities.
     */
    @Transactional(readOnly = true)
    public Page<TBEnvironmentUpdateDTO> findByCriteria(TBEnvironmentUpdateCriteria criteria, Pageable page) {
        log.debug("find by criteria : {}, page: {}", criteria, page);
        final Specification<TBEnvironmentUpdate> specification = createSpecification(criteria);
        return tBEnvironmentUpdateRepository.findAll(specification, page)
            .map(tBEnvironmentUpdateMapper::toDto);
    }

    /**
     * Return the number of matching entities in the database
     *
     * @param criteria The object which holds all the filters, which the entities should match.
     * @return the number of matching entities.
     */
    @Transactional(readOnly = true)
    public long countByCriteria(TBEnvironmentUpdateCriteria criteria) {
        log.debug("count by criteria : {}", criteria);
        final Specification<TBEnvironmentUpdate> specification = createSpecification(criteria);
        return tBEnvironmentUpdateRepository.count(specification);
    }

    /**
     * Function to convert TBEnvironmentUpdateCriteria to a {@link Specification}
     */
    private Specification<TBEnvironmentUpdate> createSpecification(TBEnvironmentUpdateCriteria criteria) {
        Specification<TBEnvironmentUpdate> specification = Specification.where(null);
        if (criteria != null) {
            if (criteria.getId() != null) {
                specification = specification.and(buildSpecification(criteria.getId(), TBEnvironmentUpdate_.id));
            }
            if (criteria.getIndex() != null) {
                specification = specification.and(buildRangeSpecification(criteria.getIndex(), TBEnvironmentUpdate_.index));
            }
            if (criteria.getTimes() != null) {
                specification = specification.and(buildRangeSpecification(criteria.getTimes(), TBEnvironmentUpdate_.times));
            }
            if (criteria.getTbEnvironmentalParameterId() != null) {
                specification = specification.and(buildSpecification(criteria.getTbEnvironmentalParameterId(),
                    root -> root.join(TBEnvironmentUpdate_.tbEnvironmentalParameter, JoinType.LEFT).get(TBEnvironmentalParameter_.id)));
            }
            if (criteria.getTbActivityId() != null) {
                specification = specification.and(buildSpecification(criteria.getTbActivityId(),
                    root -> root.join(TBEnvironmentUpdate_.tbActivity, JoinType.LEFT).get(TBActivity_.id)));
            }
            if (criteria.getTbEquipmentOfCustomerId() != null) {
                specification = specification.and(buildSpecification(criteria.getTbEquipmentOfCustomerId(),
                    root -> root.join(TBEnvironmentUpdate_.tbEquipmentOfCustomer, JoinType.LEFT).get(TBEquipmentOfCustomer_.id)));
            }
        }
        return specification;
    }

    @Transactional
    public TBActivityDTO createActivityEnv(ActivityEnvDTO activityEnvDTO, MultipartFile[] images, Pageable pageable) {
        Optional<UserDTO> currentUser = userService.getCurrentUserDTO();

        TBActivityTypeDTO tbActivityTypeDTO = tBActivityTypeQueryService.findActivityTypeByName(Constants.ACTIVE_TYPE_UPDATE_ENV, pageable);
        TBActivityDTO activityDTO = new TBActivityDTO();
        activityDTO.setCreatedById(currentUser.get().getId());
        activityDTO.setActivityTypeId(tbActivityTypeDTO.getId());
        activityDTO.setDescription(activityEnvDTO.getDescription());
        activityDTO.setExecuteDate(activityEnvDTO.getExecuteDate());
        activityDTO.setCropId(activityEnvDTO.getCropId());
        activityDTO.setAgeDay(tBCropQueryService.getAgeDayByCropID(activityEnvDTO.getCropId(), activityEnvDTO.getExecuteDate()));
        activityDTO.setCreatedDate(Instant.now());
        activityDTO = tBActivityQueryService.saveUploadedFiles(activityDTO, images, "Env");
        TBActivityDTO result = tBActivityService.save(activityDTO);

        for (ActivityEnvDetailDTO item : activityEnvDTO.getEnvDetail()) {
            if (item.getIndex() != null && item.getName() != null) {
                TBEnvironmentalParameterDTO envParam = findEnvParameterByName(item.getName(), pageable);
                if (envParam != null) {
                    TBEnvironmentUpdateDTO tbEnvironmentUpdate = new TBEnvironmentUpdateDTO();
                    tbEnvironmentUpdate.setTbActivityId(result.getId());
                    tbEnvironmentUpdate.setIndex(item.getIndex());
                    tbEnvironmentUpdate.setTbEnvironmentalId(envParam.getId());
                    tbEnvironmentUpdate.setTimes(getTimesByDateAndParamId(Instant.now(), envParam.getId()));
                    tBEnvironmentUpdateService.save(tbEnvironmentUpdate);
                }
            }
        }
        return result;
    }

    @Transactional
    public TBActivityDTO updateActivityEnv(ActivityEnvDTO activityEnvDTO, MultipartFile[] images, Pageable pageable) {
        Optional<UserDTO> currentUser = userService.getCurrentUserDTO();

        Optional<TBActivityDTO> tBActivityDTOOptional = tBActivityService.findOne(activityEnvDTO.getActivityId());
        if (tBActivityDTOOptional.isPresent()) {
            TBActivityDTO activityDTO = tBActivityDTOOptional.get();

            // update data activity
            activityDTO.setModifiedById(currentUser.get().getId());
            activityDTO.setDescription(activityEnvDTO.getDescription());
            activityDTO.setModifiedDate(Instant.now());
            if(activityDTO.getExecuteDate() != activityEnvDTO.getExecuteDate()){
                activityDTO.setExecuteDate(activityEnvDTO.getExecuteDate());
                activityDTO.setAgeDay(tBCropQueryService.getAgeDayByCropID(activityDTO.getCropId(), activityEnvDTO.getExecuteDate()));
            }
            activityDTO = tBActivityQueryService.updateUploadedFiles(activityDTO, images, "Env", activityEnvDTO.getMedia_del());
            TBActivityDTO result = tBActivityService.save(activityDTO);


            for (ActivityEnvDetailDTO item : activityEnvDTO.getEnvDetail()) {
                if (item.getIndex() != null && item.getName() != null) {
                    TBEnvironmentalParameterDTO envParam = findEnvParameterByName(item.getName(), pageable);
                    if (envParam != null) {
                        TBEnvironmentUpdateDTO tbEnvironmentUpdate =
                            findEnvParameterByActivityIdAndEnvParamId(result.getId(), envParam.getId(), pageable);
                        if (tbEnvironmentUpdate != null) {
                            tbEnvironmentUpdate.setIndex(item.getIndex());
                            tBEnvironmentUpdateService.save(tbEnvironmentUpdate);
                        } else {
                            TBEnvironmentUpdateDTO tbEnvUpdate = new TBEnvironmentUpdateDTO();
                            tbEnvUpdate.setTbActivityId(result.getId());
                            tbEnvUpdate.setIndex(item.getIndex());
                            tbEnvUpdate.setTbEnvironmentalId(envParam.getId());
                            tbEnvUpdate.setTimes(getTimesByDateAndParamId(result.getExecuteDate(), envParam.getId()));
                            tBEnvironmentUpdateService.save(tbEnvUpdate);
                        }
                    }
                }
            }
            return result;
        } else {
            return null;
        }
    }

    private int getTimesByDateAndParamId(Instant date, Long paramId) {
        String query = "SELECT eu.id FROM tb_activity as a\n" +
            "join tb_environment_update as eu\n" +
            "on a.id = eu.tb_activity_id\n" +
            "where eu.tb_environmental_parameter_id = :paramId and DATE(execute_date) = DATE_FORMAT(:date, '%Y-%m-%d')";

        Query envStandardQuery = entityManager.createNativeQuery(query);
        envStandardQuery.setParameter("paramId", paramId);
        envStandardQuery.setParameter("date", date);
        int time_curent = envStandardQuery.getResultList().size();
        return time_curent + 1;
    }

    private TBEnvironmentalParameterDTO findEnvParameterByName(String name, Pageable pageable) {
        TBEnvironmentalParameterCriteria criteria = new TBEnvironmentalParameterCriteria();
        StringFilter nameFilter = new StringFilter();
        nameFilter.setEquals(name);
        criteria.setName(nameFilter);
        Page<TBEnvironmentalParameterDTO> page = tBEnvironmentalParameterQueryService.findByCriteria(criteria, pageable);
        return page.getContent().size() == 0 ? null : page.getContent().get(0);
    }

    private TBEnvironmentUpdateDTO findEnvParameterByActivityIdAndEnvParamId(Long activityId, Long envParamId, Pageable pageable) {
        TBEnvironmentUpdateCriteria criteria = new TBEnvironmentUpdateCriteria();
        LongFilter activityIdFilter = new LongFilter();
        LongFilter envParamIdFilter = new LongFilter();
        activityIdFilter.setEquals(activityId);
        envParamIdFilter.setEquals(envParamId);
        criteria.setTbActivityId(activityIdFilter);
        criteria.setTbEnvironmentalParameterId(envParamIdFilter);
        Page<TBEnvironmentUpdateDTO> page = findByCriteria(criteria, pageable);
        return page.getContent().size() == 0 ? null : page.getContent().get(0);
    }

    public List<TBEnvironmentUpdateDisplayDTO> getListTBEnvironmentUpdatesDisplay(Long cropId) {
        //Get tbguideline by tbcropID
        Optional<TBCropDTO> tbCropDTO = tBCropService.findOne(cropId);
        if(tbCropDTO.isPresent()) {
            List<TBEnvironmentUpdateDisplayDTO> result = new ArrayList<>();
            List<TBEnvironmentUpdate> tbEnvironmentUpdate = tBEnvironmentUpdateRepository.findAll().stream()
                .filter(item -> item.getTbActivity() != null
                    && item.getTbActivity().getCrop() != null
                    && item.getTbActivity().getExecuteDate() != null
                    && item.getTbActivity().getCrop().getId() == cropId)
                .sorted((o1, o2) -> (o2.getTbActivity().getExecuteDate().compareTo(o1.getTbActivity().getExecuteDate())))
                .filter(distinctByKey(pr -> Arrays.asList(pr.getTbEnvironmentalParameter().getId())))
                .collect(Collectors.toList());

            List<TBEnvironmentUpdateDTO> tbEnvironmentUpdateDTO = tBEnvironmentUpdateMapper.toDto(tbEnvironmentUpdate);

            for (TBEnvironmentUpdateDTO item : tbEnvironmentUpdateDTO) {
                TBEnvironmentUpdateDisplayDTO tbEnvironmentUpdateDisplayDTO = new TBEnvironmentUpdateDisplayDTO();
                TBEnvironmentalParameterDTO envParam = tBEnvironmentalParameterService.findOne(item.getTbEnvironmentalId()).get();
                TBActivityDTO tBActivityDTO = tBActivityService.findOne(item.getTbActivityId()).get();
                tbEnvironmentUpdateDisplayDTO.setId(item.getId());
                tbEnvironmentUpdateDisplayDTO.setActivityId(tBActivityDTO.getId());
                tbEnvironmentUpdateDisplayDTO.setName(envParam.getName());
                tbEnvironmentUpdateDisplayDTO.setIndex(item.getIndex());
                tbEnvironmentUpdateDisplayDTO.setStatus(getStatusEnvironmentUpdatesDisplay(tbCropDTO.get().getTbGuidelineId(), item.getIndex(), tBActivityDTO.getAgeDay(), envParam.getId()));
                tbEnvironmentUpdateDisplayDTO.setExecuteDate(tBActivityDTO.getExecuteDate());
                result.add(tbEnvironmentUpdateDisplayDTO);
            }
            return result;
        }
        return null;
    }
    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    private Boolean getStatusEnvironmentUpdatesDisplay(Long tbGuidelineId, Double indexValue, Integer ageDay, Long envParamId) {
        log.info("tbGuidelineId:" + tbGuidelineId);
        log.info("indexValue:" + indexValue);
        log.info("ageDay" + ageDay);
        log.info("envParamId" + envParamId);
        //Get guidelineDetailId by guidelineId and shrimpAgeDay
        TBGuidelineDetailsDTO guidelineDetailsDTO = getDetailGuideLineIdByGuidelineIdAndAgeDay(tbGuidelineId, ageDay);
        if(guidelineDetailsDTO == null)
        {
            log.info("detail guideline is null");
            return false;
        }

        //Get limit record by guidelineDetailId and envParameterId
        TBLimitsDTO limitsDTO = getLimitByDetailGuidelineIdAndEnvParamId(guidelineDetailsDTO.getId(), envParamId);
        if(limitsDTO == null)
        {
            log.info("limit is null");
            return false;
        }

        //Check exceed with upper_limit and lower_limit
        return isCheckLimit(limitsDTO, indexValue);
    }

    private TBGuidelineDetailsDTO getDetailGuideLineIdByGuidelineIdAndAgeDay(Long guideLineId, Integer shrimpAgeDay) {
        Query detailGuidelineQuery = entityManager.createNativeQuery(
            String.format(
                "select *\n" +
                    "FROM tb_guideline_details AS tbl\n" +
                    "WHERE tbl.tb_guideline_id = :tbGuideLineId\n" +
                    "AND tbl.age_day_start <= :ageDay\n" +
                    "AND tbl.age_day_end >= :ageDay\n"), TBGuidelineDetails.class);
        detailGuidelineQuery.setParameter("tbGuideLineId", guideLineId);
        detailGuidelineQuery.setParameter("ageDay", shrimpAgeDay);
        List<TBGuidelineDetailsDTO> lstGuidelineDetailsDto = tbGuidelineDetailsMapper.toDto(detailGuidelineQuery.getResultList());
        if(lstGuidelineDetailsDto != null && lstGuidelineDetailsDto.size() >0)
        {
            return lstGuidelineDetailsDto.get(0);
        }
        return  null;
    }

    private TBLimitsDTO getLimitByDetailGuidelineIdAndEnvParamId(Long detailGuideLineId, Long environmentalParameterId) {
        Query limitsQuery = entityManager.createNativeQuery(
            String.format(
                "select *\n" +
                    "FROM tb_limits AS tbl\n" +
                    "WHERE tbl.tb_guideline_details_id = :guideLineDetailId\n" +
                    "AND tbl.tb_environmental_parameter_id = :environmentalParameterId"), TBLimits.class);
        limitsQuery.setParameter("guideLineDetailId", detailGuideLineId);
        limitsQuery.setParameter("environmentalParameterId", environmentalParameterId);
        List<TBLimitsDTO> lstLimitsDTO = tbLimitsMapper.toDto(limitsQuery.getResultList());
        if(lstLimitsDTO != null && lstLimitsDTO.size() >0)
        {
            return lstLimitsDTO.get(0);
        }
        return  null;
    }

    private Boolean isCheckLimit(TBLimitsDTO limitsDTO, Double indexValue) {
        if(limitsDTO.getLowerLimit() != null && limitsDTO.getUpperLimit() != null) {
            log.info("lower limit:" + limitsDTO.getLowerLimit());
            log.info("upper limit:" + limitsDTO.getUpperLimit());
            if(indexValue >= limitsDTO.getLowerLimit() && indexValue <= limitsDTO.getUpperLimit()) {
                log.info("is check limit is false1");
                return false;
            } else {
                log.info("is check limit is true1");
                return true;
            }
        } else if(limitsDTO.getLowerLimit() == null && limitsDTO.getUpperLimit() != null) {
            if(indexValue <= limitsDTO.getUpperLimit()) {
                log.info("is check limit is false2");
                return false;
            } else {
                log.info("is check limit is true2");
                return true;
            }
        }
        else if (limitsDTO.getLowerLimit() != null && limitsDTO.getUpperLimit() == null) {
            if(indexValue >= limitsDTO.getLowerLimit()) {
                log.info("is check limit is false3");
                return false;
            } else {
                log.info("is check limit is true3");
                return true;
            }
        }
        else {
            log.info("is check limit is false4");
            return false;
        }
    }

    public Optional<ActivityEnvironmentUpdateDTO> getEnvironmentUpdateActivity(Long activityId) {
        Optional<TBActivityDTO> tbActivityDTOOptional = tBActivityService.findOne(activityId);
        if (!tbActivityDTOOptional.isPresent()) {
            return Optional.empty();
        }

        TBEnvironmentUpdateCriteria criteria = new TBEnvironmentUpdateCriteria();
        LongFilter activityIdFilter = new LongFilter();
        activityIdFilter.setEquals(activityId);
        criteria.setTbActivityId(activityIdFilter);

        TBActivityDTO tbActivityDTO = tbActivityDTOOptional.get();
        ActivityEnvironmentUpdateDTO envDTO = new ActivityEnvironmentUpdateDTO();
        envDTO.setCropId(tbActivityDTO.getCropId());
        envDTO.setExecuteDate(tbActivityDTO.getExecuteDate());
        envDTO.setMedia(tbActivityDTO.getMedia());
        envDTO.setDescription(tbActivityDTO.getDescription());
        envDTO.setExecuteBy(tbActivityDTO.getCreatedByName());
        envDTO.setEnvironmentUpdates(findByCriteria(criteria));

        return Optional.of(envDTO);
    }

    private List<UserDTO> getListUserByCustomerId(Pageable pageable, Long customerId) {
        List<UserDTO> userDTOs = userService.getAllUsers(pageable).getContent();
        List<UserDTO> userDTOByCustomers = new ArrayList<>();
        for(UserDTO userDTO : userDTOs) {
            if( userDTO.getCustomerId() == customerId) {
                userDTOByCustomers.add(userDTO);
            }
        }
        return userDTOByCustomers;
    }

    private List<NotificationEnvAutoDTO> getNotificationEnvAutoDTOs() {
        List<NotificationEnvAutoDTO> notificationEnvAutoDTOs = new ArrayList<>();

        //Get list activities exceed limit and group by tbEntityId
        Map<Long, List<TBEnvironmentUpdate>> lst = tBEnvironmentUpdateRepository.findAll().stream()
            .filter(item -> item.getTbActivity() != null
                && item.getTbActivity().getCrop() != null
                && item.getTbActivity().getCrop().getTbGuideline() != null
                && item.getTbEnvironmentalParameter() != null
                && item.getTbActivity().getDescription() == null
                && item.getTbActivity().getModifiedDate() == null
                && getStatusEnvironmentUpdatesDisplay(item.getTbActivity().getCrop().getTbGuideline().getId(),
                    item.getIndex(), item.getTbActivity().getAgeDay(), item.getTbEnvironmentalParameter().getId()))
            .filter(distinctByKey(pr -> Arrays.asList(pr.getTbActivity().getId())))
            .collect(Collectors.groupingBy(item -> item.getTbActivity().getCrop().getTbEntity().getId()));

        return notificationEnvAutoDTOs;
    }

    @Transactional
    public void sendNotificationEnvAuto(List<NotificationEnvAutoDTO> notificationEnvAutoDTOs, Pageable pageable) {
        for(NotificationEnvAutoDTO notificationEnvAutoDTO : notificationEnvAutoDTOs) {
            //Get Entity
            TBEntityDTO tBEntityDTO = tBEntityService.findOne(notificationEnvAutoDTO.getTbEntityId()).get();

            //Get latest Crop by EntityId
            TBCropCriteria criteria = new TBCropCriteria();
            LongFilter tBEntityIdFilter = new LongFilter();
            tBEntityIdFilter.setEquals(tBEntityDTO.getId());
            criteria.setNetHouseId(tBEntityIdFilter);
            Page<TBCropDTO> page = tBCropQueryService.findByCriteria(criteria, pageable);

            //Notification activity env exceed limit
            if (notificationEnvAutoDTO.getActivityIds().size() > 0
                && page.getContent().size() > 0) {
                TBCropDTO tbCropDTO = page.getContent().get(0);

                List<UserDTO> userDTOs = getListUserByCustomerId(pageable, tBEntityDTO.getTbCustomerId());
                String titleContentEnv = "";
                if (notificationEnvAutoDTO.getActivityIds().size() == 1) {
                    TBActivityDTO tbActivityDTO = tBActivityService.findOne(notificationEnvAutoDTO.getActivityIds().get(0)).get();
                    TBEnvironmentUpdateCriteria envUpdateCriteria = new TBEnvironmentUpdateCriteria();
                    LongFilter activityIdFilter = new LongFilter();
                    activityIdFilter.setEquals(tbActivityDTO.getId());
                    envUpdateCriteria.setTbActivityId(activityIdFilter);
                    List<TBEnvironmentUpdateDTO> tbEnvironmentUpdateDTOS = this.findByCriteria(envUpdateCriteria);
                    titleContentEnv = "Thông số";

                    for (TBEnvironmentUpdateDTO tbEnvironmentUpdateDTO : tbEnvironmentUpdateDTOS) {
                        TBEnvironmentalParameterDTO tbEnvironmentalParameterDTO = tBEnvironmentalParameterService.findOne(tbEnvironmentUpdateDTO.getId()).get();
                        titleContentEnv = titleContentEnv + " " + tbEnvironmentalParameterDTO.getDescription();
                    }

                    String tbCropType = "";
                    Optional<TBCropTypeDTO> cropType = tbCropTypeService.findOne(tbCropDTO.getTbCropTypeId());
                    if(cropType.isPresent()) {
                        tbCropType = cropType.get().getName();
                    }
                    titleContentEnv = titleContentEnv + " trên " + tBEntityDTO.getName()  + "(" + tbCropType + ") vượt ngưỡng.";
                } else {
                    titleContentEnv = notificationEnvAutoDTO.getActivityIds().size() + " activities trên " + tBEntityDTO.getName() + " vượt ngưỡng.";
                }
                for (UserDTO userDTO : userDTOs) {
                    if (userDTO.getFcmToken() != null && !userDTO.getFcmToken().isEmpty()) {
                        PushNotificationRequest request = new PushNotificationRequest(Constants.NOTIFICATION_TITLE_ENV_UPDATE
                            , titleContentEnv
                            , userDTO.getFcmToken()
                            , Constants.NOTIFICATION_REQUEST_TYPE_ENV_UPDATE
                            , userDTO.getId()
                            , tBEntityDTO.getId()
                            , tbCropDTO.getId()
                            , tbCropDTO.getTbCropTypeId());
                        if(isTestSendNotification == 0) {
                            pushNotificationService.sendPushNotificationToToken(request);
                        } else {
                            log.info("----Send notification----- :" + titleContentEnv + " to " + userDTO.getFullName());
                        }
                    }
                }
            }
            else {
                continue;
            }
        }
    }

}
