package vn.azteam.tpf.web.rest;

import com.codahale.metrics.annotation.Timed;
import io.github.jhipster.service.filter.LongFilter;
import io.github.jhipster.service.filter.StringFilter;
import io.github.jhipster.web.util.ResponseUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.casbin.jcasbin.main.Enforcer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import vn.azteam.tpf.service.*;
import vn.azteam.tpf.service.dto.*;
import vn.azteam.tpf.service.util.PageableUtil;
import vn.azteam.tpf.service.util.UserRoleUtil;
import vn.azteam.tpf.web.rest.errors.BadRequestAlertException;
import vn.azteam.tpf.web.rest.errors.ForbiddenException;
import vn.azteam.tpf.web.rest.util.HeaderUtil;
import vn.azteam.tpf.web.rest.util.PaginationUtil;
import vn.azteam.tpf.web.rest.util.RandomStringUtil;

import javax.servlet.http.HttpServletRequest;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Instant;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static vn.azteam.tpf.Constants.Constants.*;
import static vn.azteam.tpf.security.contants.Contants.CUSID_API_KEY;

/**
 * REST controller for managing TBCrop.
 */
@RestController
@RequestMapping("/api")
//@SecurityRequirement(name = "api")
public class TBCropResource {

    private final Logger log = LoggerFactory.getLogger(TBCropResource.class);
    protected final Log logger = LogFactory.getLog(this.getClass());

    private static final String ENTITY_NAME = "tBCrop";

    private final TBCropService tBCropService;

    private final TBActivityQueryService tBActivityQueryService;

    private final TBCropQueryService tBCropQueryService;

    private final UserService userService;

    private final UserRoleUtil userRoleUtil;

    private final Enforcer enforcer;

    private final TBEntityService tbEntityService;

    private final TBObjectUpdateService tbObjectUpdateService;

    private final PageableUtil pageableUtil;

    private final TBCustomerService tbCustomerService;

    private final TBAddressService tbAddressService;

    public TBCropResource(
        TBCropService tBCropService,
        TBActivityQueryService tBActivityQueryService,
        TBCropQueryService tBCropQueryService,
        UserRoleUtil userRoleUtil,
        Enforcer enforcer,
        UserService userService,
        TBEntityService tbEntityService,
        TBObjectUpdateService tbObjectUpdateService, PageableUtil pageableUtil, TBCustomerService tbCustomerService, TBAddressService tbAddressService) {
        this.tBCropService = tBCropService;
        this.tBActivityQueryService = tBActivityQueryService;
        this.tBCropQueryService = tBCropQueryService;
        this.userService = userService;
        this.enforcer = enforcer;
        this.userRoleUtil = userRoleUtil;
        this.tbEntityService = tbEntityService;
        this.tbObjectUpdateService = tbObjectUpdateService;
        this.pageableUtil = pageableUtil;
        this.tbCustomerService = tbCustomerService;
        this.tbAddressService = tbAddressService;
    }

    /**
     * POST  /tb-crops : Create a new tBCrop.
     *
     * @param tBCropDTO the tBCropDTO to create
     * @return the ResponseEntity with status 201 (Created) and with body the new tBCropDTO, or with status 400 (Bad Request) if the tBCrop has already an ID
     * @throws URISyntaxException if the Location URI syntax is incorrect
     */
    @PostMapping("/tb-crops")
    @Timed
    public ResponseEntity<TBCropDTO> createTBCrop(@RequestBody TBCropDTO tBCropDTO) throws URISyntaxException {
        log.debug("REST request to save TBCrop : {}", tBCropDTO);
        //Set created by to current user login
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        if (tBCropDTO.getId() != null) {
            throw new BadRequestAlertException("1047", ENTITY_NAME, "1047");
        }
        if (currentUser.getCustomerId() == null) {
            throw new BadRequestAlertException("1018", ENTITY_NAME, "1018");
        }
        if (tBCropDTO.getTbCropTypeId() == null) {
            throw new BadRequestAlertException("1031", ENTITY_NAME, "1031");
        }
        if (!userRoleUtil.currentUserHasPermissionByEntityId(tBCropDTO.getNetHouseId())) {
            throw new BadRequestAlertException("1018", ENTITY_NAME, "1018");
        }
        TBEntityDTO tbEntityDTO = tbEntityService.findOne(tBCropDTO.getNetHouseId()).get();
        if (currentUser.getCustomerId() != null
            && !currentUser.getCustomerId().equals(tbEntityDTO.getTbCustomerId())) {
            throw new BadRequestAlertException("1019", ENTITY_NAME, "1019");
        }
        //Set created date to current timestamp
        tBCropDTO.setCreatedDate(Instant.now());
        tBCropDTO.setStartDate(tBCropDTO.getCreatedDate());
        tBCropDTO.setCreatedById(currentUser.getUserId());
        tBCropDTO.setTbCustomerId(currentUser.getCustomerId());
        tBCropDTO.setStatus(ENUM_CROP_STATUS.STATUS_ARE_ACTIVE.name());
        TBCropDTO result = null;
        Boolean hasViolationException = false;
        do {
            try {
                String qrCode = RandomStringUtil.generateRandomStringFromUUID(8);
                tBCropDTO.setQrCode(qrCode);
                result = tBCropService.save(tBCropDTO);
            } catch (org.springframework.dao.DataIntegrityViolationException ex) {
                if (ex.getMessage().contains("ux_tb_crop_qr_code")) {
                    hasViolationException = true;
                } else {
                    throw ex;
                }
            }
        }
        while (hasViolationException);
        return ResponseEntity.created(new URI("/api/tb-crops/" + result.getId()))
            .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
            .body(result);
    }

    /**
     * PUT  /tb-crops : Updates an existing tBCrop.
     *
     * @param tBCropDTO the tBCropDTO to update
     * @return the ResponseEntity with status 200 (OK) and with body the updated tBCropDTO,
     * or with status 400 (Bad Request) if the tBCropDTO is not valid,
     * or with status 500 (Internal Server Error) if the tBCropDTO couldn't be updated
     */
    @PutMapping("/tb-crops")
    @Timed
    public ResponseEntity<TBCropDTO> updateTBCrop(@RequestBody TBCropDTO tBCropDTO) {
        log.debug("REST request to update TBCrop : {}", tBCropDTO);
        if (tBCropDTO.getId() == null) {
            throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull");
        }
        //Set created date to current timestamp
        tBCropDTO.setModifiedDate(Instant.now());
        //Set created by to current user login
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        tBCropDTO.setModifiedById(currentUser.getUserId());

        TBCropDTO result = tBCropService.save(tBCropDTO);
        return ResponseEntity.ok()
            .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, tBCropDTO.getId().toString()))
            .body(result);
    }

    /**
     * GET  /tb-crops-dropdown-list : get all the tBCrops for dropdown options.
     *
     * @param criteria the criterias which the requested entities should match
     * @return the ResponseEntity with status 200 (OK) and the list of tBCrops in body
     */
    @GetMapping("/tb-crops-dropdown-list")
    @Timed
    public ResponseEntity<List<TBCropDTO>> getAllTBCropsForDropdown(TBCropCriteria criteria) {
        log.debug("REST request to get TBCrops by criteria: {}", criteria);
        Page<TBCropDTO> page = tBCropQueryService.findByCriteria(criteria, Pageable.unpaged());

        //Authorize get list crop by customer of current user
        List<TBCropDTO> result = page.getContent().stream()
            .filter(item -> userRoleUtil.currentUserHasPermissionByCustomerId(item.getId())
                && userRoleUtil.currentUserHasPermissionByCropId(item.getId()))
            .sorted(Comparator.comparing(
                TBCropDTO::getCreatedDate,
                Comparator.nullsFirst(Comparator.naturalOrder())).reversed())
            .collect(Collectors.toList());

        return ResponseEntity.ok().headers(null).body(result);
    }

    /**
     * GET  /tb-crops : get all the tBCrops.
     *
     * @param pageable the pagination information
     * @param criteria the criterias which the requested entities should match
     * @return the ResponseEntity with status 200 (OK) and the list of tBCrops in body
     */
    @GetMapping("/tb-crops")
    @Timed
    public ResponseEntity<List<TBCropDTO>> getAllTBCrops(TBCropCriteria criteria, Pageable pageable) {
        log.debug("REST request to get TBCrops by criteria: {}", criteria);
        Page<TBCropDTO> page = tBCropQueryService.findByCriteria(criteria, Pageable.unpaged());

        //Authorize get list crop by customer of current user
        List<TBCropDTO> result = page.getContent().stream()
            .filter(item -> userRoleUtil.currentUserHasPermissionByCustomerId(item.getId())
                && userRoleUtil.currentUserHasPermissionByCropId(item.getId()))
            .sorted(Comparator.comparing(
                TBCropDTO::getCreatedDate,
                Comparator.nullsFirst(Comparator.naturalOrder())).reversed())
            .collect(Collectors.toList());

        Page<TBCropDTO> pageResult = pageableUtil.changeTBCropDTOToPageFromList(result, pageable);
        for (TBCropDTO itemResult : result) {
            logger.error("Start date: " + itemResult.getStartDate());
        }
        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(pageResult, "/api/tb-crops");
        return ResponseEntity.ok().headers(headers).body(pageResult.getContent());
    }

    @GetMapping("/ots/tb-crops-by-customer")
    @Timed
    public ResponseEntity<List<TBCropDTO>> getTBCropsByCustomer(HttpServletRequest request, TBCropCriteria criteria, Pageable pageable) {
        log.debug("REST request to get TBCrops by criteria: {}", criteria);
        Page<TBCropDTO> page = tBCropQueryService.findByCriteria(criteria, Pageable.unpaged());
        Long customer_id = Long.parseLong(request.getHeader(CUSID_API_KEY));
        List<TBCropDTO> result = page.getContent().stream()
            .filter(item -> item.getTbCustomerId().equals(customer_id))
            .sorted(Comparator.comparing(
                TBCropDTO::getCreatedDate,
                Comparator.nullsFirst(Comparator.naturalOrder())).reversed())
            .collect(Collectors.toList());

        Page<TBCropDTO> pageResult = pageableUtil.changeTBCropDTOToPageFromList(result, pageable);
        for (TBCropDTO itemResult : result) {
            logger.error("Start date: " + itemResult.getStartDate());
        }
        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(pageResult, "/api/ots/tb-crops-by-customer");
        return ResponseEntity.ok().headers(headers).body(pageResult.getContent());
    }

    /**
     * GET  /tb-crops/:cropId : get the "id" tBCrop.
     *
     * @param cropId the id of the tBCropDTO to retrieve
     * @return the ResponseEntity with status 200 (OK) and with body the tBCropDTO, or with status 404 (Not Found)
     */
    @GetMapping("/ots/tb-crops/{cropId}")
    @Timed
    public ResponseEntity<TBCropDTO> getTBCropOTS(@PathVariable Long cropId, HttpServletRequest request) {
        log.debug("REST request to get TBCrop : {}", cropId);
        Long customer_id = Long.parseLong(request.getHeader(CUSID_API_KEY));

        Optional<TBCropDTO> tBCropDTO = tBCropService.findOne(cropId);
        if (!tBCropDTO.get().getTbCustomerId().equals(customer_id)) {
            throw new ForbiddenException();
        }
        return ResponseUtil.wrapOrNotFound(tBCropDTO);
    }

    /**
     * GET  /tb-crops/count : count all the tBCrops.
     *
     * @param criteria the criterias which the requested entities should match
     * @return the ResponseEntity with status 200 (OK) and the count in body
     */
    @GetMapping("/tb-crops/count")
    @Timed
    public ResponseEntity<Long> countTBCrops(TBCropCriteria criteria) {
        log.debug("REST request to count TBCrops by criteria: {}", criteria);
        return ResponseEntity.ok().body(tBCropQueryService.countByCriteria(criteria));
    }

    /**
     * GET  /tb-crops/:id : get the "id" tBCrop.
     *
     * @param id the id of the tBCropDTO to retrieve
     * @return the ResponseEntity with status 200 (OK) and with body the tBCropDTO, or with status 404 (Not Found)
     */
    @GetMapping("/tb-crops/{id}")
    @Timed
    public ResponseEntity<TBCropDTO> getTBCrop(@PathVariable Long id) {
        log.debug("REST request to get TBCrop : {}", id);
        Optional<TBCropDTO> tBCropDTO = tBCropService.findOne(id);
        //@CUONGLT - Filter scope customer's data
        if (!userRoleUtil.currentUserHasPermissionByCropId(id)) {
            throw new BadRequestAlertException("1018", ENTITY_NAME, "1018");
        }
        return ResponseUtil.wrapOrNotFound(tBCropDTO);
    }

    /**
     * GET  /tb-crops-detail/:id : get the "id" tBCrop.
     *
     * @param id the id of the tBCropDTO to retrieve
     * @return the ResponseEntity with status 200 (OK) and with body the tBCropDTO, or with status 404 (Not Found)
     */
    @GetMapping("/tb-crops-detail/{id}")
    @Timed
    public ResponseEntity<TBCropDetailDTO> getDetailTBCropForWeb(@PathVariable Long id, Pageable pageable) {
        log.debug("REST request to get TBCrop detail for web : {}", id);
        return getCropDetailDTOResponseEntity(id, pageable, true);
    }

    /**
     * GET  /tb-crops-detail-for-app/:id : get the "id" tBCrop.
     *
     * @param id the id of the tBCropDTO to retrieve
     * @return the ResponseEntity with status 200 (OK) and with body the tBCropDTO, or with status 404 (Not Found)
     */
    @GetMapping("/tb-crops-detail-for-app/{id}")
    @Timed
    public ResponseEntity<TBCropDetailDTO> getDetailTBCropForApp(@PathVariable Long id, Pageable pageable) {
        log.debug("REST request to get TBCrop detail for app : {}", id);
        return getCropDetailDTOResponseEntity(id, pageable, false);
    }

    /**
     * GET  /ots/tb-crops-detail/:id : get the "id" tBCrop.
     *
     * @param id the id of the tBCropDTO to retrieve
     * @return the ResponseEntity with status 200 (OK) and with body the tBCropDTO, or with status 404 (Not Found)
     */
    @GetMapping("/ots/tb-crops-detail/{id}")
    @Timed
    public ResponseEntity<TBCropDetailDTO> getDetailTBCropForOts(@RequestParam(required = false) String type, @PathVariable Long id, HttpServletRequest request, Pageable pageable) {
        log.debug("REST request to get TBCrop detail for app : {}", id);

        return getCropDetailDTOResponseEntityOts(type, id, request, pageable);
    }

    /**
     * GET  /tb-crops/:qrCode : get the "qrCode" tBCrop.
     *
     * @param qrCode the qrCode of the tBCropDTO to retrieve
     * @return the ResponseEntity with status 200 (OK) and with body the tBCropDTO, or with status 404 (Not Found)
     */
    @GetMapping("/tb-crops-scan-qrCode/{qrCode}")
    @Timed
    public ResponseEntity<TBCropDetailDTO> getTBCropScanQRCode(@PathVariable String qrCode, Pageable pageable) {
        TBCropCriteria tbCropCriteria = new TBCropCriteria();
        StringFilter qrCodeFilter = new StringFilter();
        qrCodeFilter.setEquals(qrCode);
        tbCropCriteria.setQrCode(qrCodeFilter);
        List<TBCropDTO> tBCropDTOs = tBCropQueryService.findByCriteria(tbCropCriteria);
        List<TBCropDTO> listTBCropDTOs;
        if (tBCropDTOs.size() > 0) {
            listTBCropDTOs = tBCropDTOs.stream()
                .filter(item -> userRoleUtil.currentUserHasPermissionByCropId(item.getId()))
                .collect(Collectors.toList());

            return listTBCropDTOs.size() > 0 ? this.getDetailTBCropForWeb(listTBCropDTOs.get(0).getId(), pageable) : null;
        }
        return ResponseEntity.ok().headers(null).body(null);
    }

    /**
     * Add or delete crop's person in charges
     *
     * @param cropPersonInChargeDTO
     * @return
     */
    @PutMapping("/update-person-in-charge")
    @Timed
    public ResponseEntity<TBCropDTO> updatePersonInCharge(@RequestBody CropPersonInChargeDTO cropPersonInChargeDTO) {
        log.debug("REST request to update PIC : {}", cropPersonInChargeDTO);
        if (cropPersonInChargeDTO.getCropId() == null) {
            throw new BadRequestAlertException("1039", ENTITY_NAME, "1039");
        }
        List<Long> listAssignmentPrev = userRoleUtil.getListUserIdByCropId(cropPersonInChargeDTO.getCropId());
        Optional<TBCropDTO> tBCropDTO = tBCropService.updateCropPersonInCharge(cropPersonInChargeDTO);
        if (null != tBCropDTO) {
            sendNotificationPersonInCharge(cropPersonInChargeDTO, listAssignmentPrev);
        }
        return ResponseUtil.wrapOrNotFound(tBCropDTO);
    }


    /**
     * DELETE  /tb-crops/:id : delete the "id" tBCrop.
     *
     * @param id the id of the tBCropDTO to delete
     * @return the ResponseEntity with status 200 (OK)
     */
    @DeleteMapping("/tb-crops/{id}")
    @Timed
    public ResponseEntity<Void> deleteTBCrop(@PathVariable Long id) {
        log.debug("REST request to delete TBCrop : {}", id);
        TBCropDTO cropDTO = tBCropService.findOne(id).get();
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        cropDTO.setDeletedDate(Instant.now());
        cropDTO.setDeletedById(currentUser.getId());
        tBCropService.save(cropDTO);
        return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, id.toString())).build();
    }

    /**
     * SEARCH  /_search/tb-crops?query=:query : search for the tBCrop corresponding
     * to the query.
     *
     * @param query    the query of the tBCrop search
     * @param pageable the pagination information
     * @return the result of the search
     */
    @GetMapping("/_search/tb-crops")
    @Timed
    public ResponseEntity<List<TBCropDTO>> searchTBCrops(
        @RequestParam(required = false) String query,
        @RequestParam(required = false) Long areaId,
        @RequestParam(required = false) Long netHouseId,
        Pageable pageable) {
        log.debug("REST request to search for a page of TBCrops for query {}", query);
        Page<TBCropDTO> page = tBCropQueryService.searchCrop(query, areaId, netHouseId, Pageable.unpaged());
        List<TBCropDTO> result = page.getContent().stream()
            .filter(item -> userRoleUtil.currentUserHasPermissionByCustomerId(item.getId())
                && userRoleUtil.currentUserHasPermissionByCropId(item.getId()))
            .sorted(Comparator.comparing(
                TBCropDTO::getCreatedDate,
                Comparator.nullsFirst(Comparator.naturalOrder())).reversed())
            .collect(Collectors.toList());
        Page<TBCropDTO> pageResult = pageableUtil.changeTBCropDTOToPageFromList(result, pageable);
        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(pageResult, "/api/_search/tb-crops");
        return ResponseEntity.ok().headers(headers).body(pageResult.getContent());
    }

    /**
     * Get crop detail by id
     *
     * @param id
     * @param pageable
     * @param isRequestedFromWeb
     * @return
     */
    private ResponseEntity<TBCropDetailDTO> getCropDetailDTOResponseEntity(
        @PathVariable Long id,
        Pageable pageable,
        Boolean isRequestedFromWeb) {
        Optional<TBCropDTO> tBCropDTO = tBCropService.findOne(id);
        if (!userRoleUtil.currentUserHasPermissionByCropId(tBCropDTO.get().getId())) {
            throw new BadRequestAlertException("1018", ENTITY_NAME, "1018");
        }
        Optional<UserDTO> currentUser = userService.getCurrentUserDTO();
        TBCropDetailDTO tbCropDetailDTO = new TBCropDetailDTO();
        tbCropDetailDTO.setTbCropDTO(tBCropDTO.get());
        // Get list of activity
        TBActivityCriteria criteria = new TBActivityCriteria();
        LongFilter cropFilter = new LongFilter();
        cropFilter.setEquals(id);
        criteria.setCropId(cropFilter);
        List<TBActivityDTO> allActivities = tBActivityQueryService.findByCriteria(criteria).stream()
            .sorted(Comparator.comparing(
                TBActivityDTO::getExecuteDate,
                Comparator.nullsLast(Comparator.naturalOrder())).reversed())
            .collect(Collectors.toList());
        //remove env activities automatically
        allActivities
            .removeIf(activity -> ACTIVE_TYPE_UPDATE_ENV.equals(activity.getActivityTypeName())
                && activity.getCreatedById() == null);

        // Lo Uom
        if (tBCropDTO.get().getTbCropTypeId() == 1) {
            // Get sowing Date
            TBActivityDTO nurseryActivity = allActivities.stream()
                .sorted(Comparator.comparing(
                    TBActivityDTO::getExecuteDate,
                    Comparator.nullsLast(Comparator.naturalOrder())))
                .filter(activity -> ACTIVE_TYPE_NURSERY.equals(activity.getActivityTypeName()))
                .findAny()
                .orElse(null);
            if (nurseryActivity != null) {
                tbCropDetailDTO.setSowingDate(nurseryActivity.getExecuteDate());
                List<TBObjectUpdateDTO> tbObjectUpdateDTOs = tbObjectUpdateService.findByTBActivityId(nurseryActivity.getId(), Pageable.unpaged());
                if (tbObjectUpdateDTOs != null && tbObjectUpdateDTOs.size() > 0) {
                    tbObjectUpdateDTOs.forEach(item -> {
                        if (item.getTbObjectParameterDTO().getName().equals(THOI_GIAN_NGAM_HAT)) {
                            item.setIndex(item.getIndex() != null && !item.getIndex().isEmpty() ? item.getIndex() : "0");
                            tbCropDetailDTO.setSeedIncubationTime(Double.valueOf(item.getIndex()));
                        }
                    });
                }
            }
        }
        //Lo Trong
        if (tBCropDTO.get().getTbCropTypeId() == 2) {
            // Get planting Date
            TBActivityDTO plantingActivity = allActivities.stream()
                .sorted(Comparator.comparing(
                    TBActivityDTO::getExecuteDate,
                    Comparator.nullsLast(Comparator.naturalOrder())))
                .filter(activity -> ACTIVE_TYPE_PLANTING.equals(activity.getActivityTypeName()))
                .findAny()
                .orElse(null);

            tbCropDetailDTO.setPlantingDate(plantingActivity != null ? plantingActivity.getExecuteDate() : null);
            List<Long> listActivities = allActivities.stream().map(TBActivityDTO::getId).collect(Collectors.toList());
            List<TBObjectUpdateDTO> tbObjectUpdateDTOs = tbObjectUpdateService.findByInListTBActivityId(listActivities, Pageable.unpaged());

            if (tbObjectUpdateDTOs != null && tbObjectUpdateDTOs.size() > 0) {
                tbObjectUpdateDTOs.forEach(item -> {
                    if (item.getTbObjectParameterDTO().getName().equals(SO_LUONG_CAY_TRONG)) {
                        item.setIndex(item.getIndex() != null && !item.getIndex().isEmpty() ? item.getIndex() : "0");
                        tbCropDetailDTO.setNumberPlants(Integer.parseInt(item.getIndex().replaceAll("[^0-9]", "")));
                        tbCropDetailDTO.setNumberCurrentPlants(Integer.parseInt(item.getIndex().replaceAll("[^0-9]", "")));
                    }
                    if (item.getTbObjectParameterDTO().getName().equals(SO_LUONG_LOAI_BO)) {
                        item.setIndex(item.getIndex() != null && !item.getIndex().isEmpty() ? item.getIndex() : "0");
                        Integer currentNumberPlants = tbCropDetailDTO.getNumberPlants() - Integer.parseInt(item.getIndex().replaceAll("[^0-9]", ""));
                        tbCropDetailDTO.setNumberCurrentPlants(currentNumberPlants > 0 ? currentNumberPlants : 0);
                    }
                });
            }
        }

        //Filter assignment croptype by customer
        if (currentUser.get().getCustomerId() != null) {
            List<Long> ListActivityTypeId = tBCropService.getListActivityTypeIdByByCustomerAndCropType(currentUser.get().getCustomerId(), tBCropDTO.get().getTbCropTypeId());
            allActivities = allActivities.stream().filter(item -> ListActivityTypeId.contains(item.getActivityTypeId())).collect(Collectors.toList());
        }
        if (isRequestedFromWeb) {
            ActivityTimelineDTO activityTimeline =
                tBCropQueryService.getActivityTimeline(id, allActivities, pageable);
            tbCropDetailDTO.setActivityTimeline(activityTimeline);
        } else {
            allActivities = pageableUtil.changeTBActivityDTOToPageFromList(allActivities, pageable).getContent();
            tbCropDetailDTO.setActivities(allActivities);
        }

        TBActivityDTO endActivity = allActivities.stream()
            .sorted(Comparator.comparing(
                TBActivityDTO::getExecuteDate,
                Comparator.nullsLast(Comparator.naturalOrder())).reversed())
            .filter(activity -> ACTIVE_TYPE_END.equals(activity.getActivityTypeName()))
            .findAny()
            .orElse(null);
        if (endActivity != null) {
            tbCropDetailDTO.setEndOfFarmingDate(endActivity.getExecuteDate());
        }

        return ResponseEntity.ok().headers(null).body(tbCropDetailDTO);
    }

    /**
     * Get crop detail by id
     *
     * @param id
     * @param pageable
     * @param request
     * @return
     */
    private ResponseEntity<TBCropDetailDTO> getCropDetailDTOResponseEntityOts(
        @RequestParam String type,
        @PathVariable Long id,
        HttpServletRequest request,
        Pageable pageable) {
        Long customerId = Long.parseLong(request.getHeader(CUSID_API_KEY));
        Optional<TBCropDTO> tBCropDTO = tBCropService.findOne(id);
        if (!tBCropDTO.isPresent()) {
            throw new BadRequestAlertException("Customer not found", ENTITY_NAME, "idinvalid");
        }
        if (!tBCropDTO.get().getTbCustomerId().equals(customerId)) {
            throw new ForbiddenException();
        }
        Optional<UserDTO> currentUser = userService.getCurrentUserDTO();
        TBCropDetailDTO tbCropDetailDTO = new TBCropDetailDTO();
        Optional<TBCustomerDTO> currentCustomerDTO = tbCustomerService.findOne(customerId);
        Optional<TBAddressDTO> locationOptional = tbAddressService.findOne(currentCustomerDTO.get().getTbAddressId());
        locationOptional.ifPresent(tbCropDetailDTO::setTbAddressDTO);
        tbCropDetailDTO.setTbCropDTO(tBCropDTO.get());
        // Get list of activity
        TBActivityCriteria criteria = new TBActivityCriteria();
        LongFilter cropFilter = new LongFilter();
        cropFilter.setEquals(id);
        criteria.setCropId(cropFilter);
        List<TBActivityDTO> allActivities = tBActivityQueryService.findByCriteria(criteria).stream()
            .filter(item -> !StringUtils.hasText(type) || item.getActivityTypeName().equals(type))
            .sorted(Comparator.comparing(
                TBActivityDTO::getExecuteDate,
                Comparator.nullsLast(Comparator.naturalOrder())).reversed())
            .collect(Collectors.toList());
        //remove env activities automatically
        allActivities
            .removeIf(activity -> ACTIVE_TYPE_UPDATE_ENV.equals(activity.getActivityTypeName())
                && activity.getCreatedById() == null);
        //Filter assignment croptype by customer
        if (currentUser.get().getCustomerId() != null) {
            List<Long> ListActivityTypeId = tBCropService.getListActivityTypeIdByByCustomerAndCropType(currentUser.get().getCustomerId(), tBCropDTO.get().getTbCropTypeId());
            allActivities = allActivities.stream().filter(item -> ListActivityTypeId.contains(item.getActivityTypeId())).collect(Collectors.toList());
        }

        allActivities = pageableUtil.changeTBActivityDTOToPageFromList(allActivities, pageable).getContent();
        tbCropDetailDTO.setActivities(allActivities);

        TBActivityDTO endActivity = allActivities.stream()
            .sorted(Comparator.comparing(
                TBActivityDTO::getExecuteDate,
                Comparator.nullsLast(Comparator.naturalOrder())).reversed())
            .filter(activity -> ACTIVE_TYPE_END.equals(activity.getActivityTypeName()))
            .findAny()
            .orElse(null);
        if (endActivity != null) {
            tbCropDetailDTO.setEndOfFarmingDate(endActivity.getExecuteDate());
        }
        // Lo Uom
        if (tBCropDTO.get().getTbCropTypeId() == 1) {
            // Get sowing Date
            TBActivityDTO nurseryActivity = allActivities.stream()
                .sorted(Comparator.comparing(
                    TBActivityDTO::getExecuteDate,
                    Comparator.nullsLast(Comparator.naturalOrder())))
                .filter(activity -> ACTIVE_TYPE_NURSERY.equals(activity.getActivityTypeName()))
                .findAny()
                .orElse(null);
            if (nurseryActivity != null) {
                tbCropDetailDTO.setSowingDate(nurseryActivity.getExecuteDate());
                List<TBObjectUpdateDTO> tbObjectUpdateDTOs = tbObjectUpdateService.findByTBActivityId(nurseryActivity.getId(), Pageable.unpaged());
                if (tbObjectUpdateDTOs != null && tbObjectUpdateDTOs.size() > 0) {
                    tbObjectUpdateDTOs.forEach(item -> {
                        if (item.getTbObjectParameterDTO().getName().equals(THOI_GIAN_NGAM_HAT)) {
                            item.setIndex(item.getIndex() != null && !item.getIndex().isEmpty() ? item.getIndex() : "0");
                            tbCropDetailDTO.setSeedIncubationTime(Double.valueOf(item.getIndex()));
                        }
                    });
                }
            }
        }
        //Lo Trong
        if (tBCropDTO.get().getTbCropTypeId() == 2) {
            // Get planting Date
            TBActivityDTO plantingActivity = allActivities.stream()
                .sorted(Comparator.comparing(
                    TBActivityDTO::getExecuteDate,
                    Comparator.nullsLast(Comparator.naturalOrder())))
                .filter(activity -> ACTIVE_TYPE_PLANTING.equals(activity.getActivityTypeName()))
                .findAny()
                .orElse(null);

            tbCropDetailDTO.setPlantingDate(plantingActivity != null ? plantingActivity.getExecuteDate() : null);
            List<Long> listActivities = allActivities.stream().map(TBActivityDTO::getId).collect(Collectors.toList());
            List<TBObjectUpdateDTO> tbObjectUpdateDTOs = tbObjectUpdateService.findByInListTBActivityId(listActivities, Pageable.unpaged());

            if (tbObjectUpdateDTOs != null && tbObjectUpdateDTOs.size() > 0) {
                tbObjectUpdateDTOs.forEach(item -> {
                    if (item.getTbObjectParameterDTO().getName().equals(SO_LUONG_CAY_TRONG)) {
                        item.setIndex(item.getIndex() != null && !item.getIndex().isEmpty() ? item.getIndex() : "0");
                        tbCropDetailDTO.setNumberPlants(Integer.parseInt(item.getIndex().replaceAll("[^0-9]", "")));
                        tbCropDetailDTO.setNumberCurrentPlants(Integer.parseInt(item.getIndex().replaceAll("[^0-9]", "")));
                    }
                    if (item.getTbObjectParameterDTO().getName().equals(SO_LUONG_LOAI_BO)) {
                        item.setIndex(item.getIndex() != null && !item.getIndex().isEmpty() ? item.getIndex() : "0");
                        Integer currentNumberPlants = tbCropDetailDTO.getNumberPlants() - Integer.parseInt(item.getIndex().replaceAll("[^0-9]", ""));
                        tbCropDetailDTO.setNumberCurrentPlants(currentNumberPlants > 0 ? currentNumberPlants : 0);
                    }
                });
            }
        }

        return ResponseEntity.ok().headers(null).body(tbCropDetailDTO);
    }

    @PostMapping("/notification/update-person-in-charge")
    public ResponseEntity sendNotificationPersonInCharge(@RequestBody CropPersonInChargeDTO cropPersonInChargeDTO, List<Long> listAssignmentPrev) {
        tBCropQueryService.sendNotificationPersonInCharge(cropPersonInChargeDTO, listAssignmentPrev);
        return new ResponseEntity<>(new PushNotificationResponse(HttpStatus.OK.value(), "Notification has been sent."), HttpStatus.OK);
    }
}
