package vn.azteam.tpf.web.rest;

import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.jhipster.service.filter.LongFilter;
import org.springframework.core.io.ResourceLoader;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import vn.azteam.tpf.Constants.Constants;
import vn.azteam.tpf.domain.TBSuppliesInWarehouse;
import vn.azteam.tpf.service.*;
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.service.dto.TBActivityDTO;
import vn.azteam.tpf.service.dto.TBActivityCriteria;
import io.github.jhipster.web.util.ResponseUtil;
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.web.bind.annotation.*;
import vn.azteam.tpf.service.dto.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import vn.azteam.tpf.service.util.UserRoleUtil;

import static vn.azteam.tpf.Constants.Constants.ACTIVE_TYPE_NURSERY;

/**
 * REST controller for managing TBActivity.
 */
@RestController
@RequestMapping("/api")
public class TBActivityResource {

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

    private static final String ENTITY_NAME = "tBActivity";

    private final TBActivityService tBActivityService;

    private final TBObjectUpdateService tbObjectUpdateService;

    private final TBActivityQueryService tBActivityQueryService;

    private final TBNurseryDetailsService tbNurseryDetailsService;

    private final TBSuppliesUsingDetailsService tbSuppliesUsingDetailsService;

    private final TBStockUpdateService tbStockUpdateService;

    private final TBEnvironmentUpdateQueryService tBEnvironmentUpdateQueryService;

    private final UserRoleUtil userRoleUtil;

    private ResourceLoader resourceLoader;

    private final ObjectMapper objectMapper;

    private final TBCropQueryService tBCropQueryService;

    private final TBActivityTypeService tbActivityTypeService;

    private final UserService userService;

    private final TBNurseryDetailsQueryService tbNurseryDetailsQueryService;

    private final TBSuppliesUsingDetailsQueryService tbSuppliesUsingDetailsQueryService;

    private final TBObjectUpdateQueryService tbObjectUpdateQueryService;

    private final TBActivityService tbActivityService;

    private final TBObjectParameterQueryService tbObjectParameterQueryService;

    private final TBCropService tbCropService;

    private final TBStockUpdateQueryService tbStockUpdateQueryService;

    private final TBSuppliesInWarehouseService tbSuppliesInWarehouseService;

    private final TBSuppliesInWarehouseQueryService tbSuppliesInWarehouseQueryService;

    private final TBBlockDetailsService tbBlockDetailsService;

    public TBActivityResource(TBActivityService tBActivityService,
                              TBObjectUpdateService tbObjectUpdateService,
                              TBActivityQueryService tBActivityQueryService,
                              TBNurseryDetailsService tbNurseryDetailsService,
                              TBSuppliesUsingDetailsService tbSuppliesUsingDetailsService,
                              TBStockUpdateService tbStockUpdateService,
                              TBEnvironmentUpdateQueryService tBEnvironmentUpdateQueryService,
                              UserRoleUtil userRoleUtil,
                              ResourceLoader resourceLoader,
                              ObjectMapper objectMapper,
                              TBCropQueryService tBCropQueryService,
                              TBActivityTypeService tbActivityTypeService,
                              UserService userService,
                              TBNurseryDetailsQueryService tbNurseryDetailsQueryService,
                              TBSuppliesUsingDetailsQueryService tbSuppliesUsingDetailsQueryService,
                              TBObjectUpdateQueryService tbObjectUpdateQueryService,
                              TBActivityService tbActivityService,
                              TBObjectParameterQueryService tbObjectParameterQueryService,
                              TBCropService tbCropService,
                              TBStockUpdateQueryService tbStockUpdateQueryService,
                              TBSuppliesInWarehouseService tbSuppliesInWarehouseService,
                              TBSuppliesInWarehouseQueryService tbSuppliesInWarehouseQueryService,
                              TBBlockDetailsService tbBlockDetailsService) {
        this.tBActivityService = tBActivityService;
        this.tbObjectUpdateService = tbObjectUpdateService;
        this.tBActivityQueryService = tBActivityQueryService;
        this.tbNurseryDetailsService = tbNurseryDetailsService;
        this.tbSuppliesUsingDetailsService = tbSuppliesUsingDetailsService;
        this.tbStockUpdateService = tbStockUpdateService;
        this.tBEnvironmentUpdateQueryService = tBEnvironmentUpdateQueryService;
        this.userRoleUtil = userRoleUtil;
        this.resourceLoader = resourceLoader;
        this.objectMapper = objectMapper;
        this.tBCropQueryService = tBCropQueryService;
        this.tbActivityTypeService = tbActivityTypeService;
        this.userService = userService;
        this.tbNurseryDetailsQueryService = tbNurseryDetailsQueryService;
        this.tbSuppliesUsingDetailsQueryService = tbSuppliesUsingDetailsQueryService;
        this.tbObjectUpdateQueryService = tbObjectUpdateQueryService;
        this.tbActivityService = tbActivityService;
        this.tbObjectParameterQueryService = tbObjectParameterQueryService;
        this.tbCropService = tbCropService;
        this.tbStockUpdateQueryService = tbStockUpdateQueryService;
        this.tbSuppliesInWarehouseService = tbSuppliesInWarehouseService;
        this.tbSuppliesInWarehouseQueryService = tbSuppliesInWarehouseQueryService;
        this.tbBlockDetailsService = tbBlockDetailsService;
    }

    /**
     * POST  /tb-activities : Create a new tBActivity.
     *
     * @param tBActivityDTO the tBActivityDTO to create
     * @return the ResponseEntity with status 201 (Created) and with body the new tBActivityDTO, or with status 400 (Bad Request) if the tBActivity has already an ID
     * @throws URISyntaxException if the Location URI syntax is incorrect
     */
    @PostMapping("/tb-activities")
    @Timed
    public ResponseEntity<TBActivityDTO> createTBActivity(@RequestBody TBActivityDTO tBActivityDTO) throws URISyntaxException {
        log.debug("REST request to save TBActivity : {}", tBActivityDTO);
        if (tBActivityDTO.getId() != null) {
            throw new BadRequestAlertException("A new tBActivity cannot already have an ID", ENTITY_NAME, "idexists");
        }
        TBActivityDTO result = tBActivityService.save(tBActivityDTO);
        return ResponseEntity.created(new URI("/api/tb-activities/" + result.getId()))
            .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
            .body(result);
    }

    /**
     * PUT  /tb-activities : Updates an existing tBActivity.
     *
     * @param tBActivityDTO the tBActivityDTO to update
     * @return the ResponseEntity with status 200 (OK) and with body the updated tBActivityDTO,
     * or with status 400 (Bad Request) if the tBActivityDTO is not valid,
     * or with status 500 (Internal Server Error) if the tBActivityDTO couldn't be updated
     * @throws URISyntaxException if the Location URI syntax is incorrect
     */
    @PutMapping("/tb-activities")
    @Timed
    public ResponseEntity<TBActivityDTO> updateTBActivity(@RequestBody TBActivityDTO tBActivityDTO) throws URISyntaxException {
        log.debug("REST request to update TBActivity : {}", tBActivityDTO);
        if (tBActivityDTO.getId() == null) {
            throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull");
        }
        TBActivityDTO result = tBActivityService.save(tBActivityDTO);
        return ResponseEntity.ok()
            .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, tBActivityDTO.getId().toString()))
            .body(result);
    }

    /**
     * GET  /tb-activities : get all the tBActivities.
     *
     * @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 tBActivities in body
     */
    @GetMapping("/tb-activities")
    @Timed
    public ResponseEntity<List<TBActivityDTO>> getAllTBActivities(TBActivityCriteria criteria, Pageable pageable) {
        log.debug("REST request to get TBActivities by criteria: {}", criteria);
        Page<TBActivityDTO> page = tBActivityQueryService.findByCriteria(criteria, pageable);
        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/tb-activities");
        return ResponseEntity.ok().headers(headers).body(page.getContent());
    }

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

    /**
     * GET  /tb-activities/:id : get the "id" tBActivity.
     *
     * @param id the id of the tBActivityDTO to retrieve
     * @return the ResponseEntity with status 200 (OK) and with body the tBActivityDTO, or with status 404 (Not Found)
     */
    @GetMapping("/tb-activities/{id}")
    @Timed
    public ResponseEntity<TBActivityDTO> getTBActivity(@PathVariable Long id) {
        log.debug("REST request to get TBActivity : {}", id);
        Optional<TBActivityDTO> tBActivityDTO = tBActivityService.findOne(id);
        return ResponseUtil.wrapOrNotFound(tBActivityDTO);
    }

    /**
     * GET  /activity-environment-update/:id : Get environment update activity
     *
     * @param id
     * @return
     */
    @GetMapping("/activity-environment-update/{id}")
    @Timed
    public ResponseEntity<ActivityEnvironmentUpdateDTO> getEnvironmentUpdateActivity(@PathVariable Long id) {
        log.debug("REST request to get EnvironmentUpdateActivity : {}", id);
        Optional<ActivityEnvironmentUpdateDTO> activityEnvironmentUpdateDTO = tBEnvironmentUpdateQueryService.getEnvironmentUpdateActivity(id);
        if(!userRoleUtil.currentUserHasPermissionByCropId(activityEnvironmentUpdateDTO.get().getCropId())){
           throw new BadRequestAlertException("1018", ENTITY_NAME, "1018");
        }
        return ResponseUtil.wrapOrNotFound(activityEnvironmentUpdateDTO);
    }

    /**
     * DELETE  /tb-activities/:id : delete the "id" tBActivity.
     *
     * @param id the id of the tBActivityDTO to delete
     * @return the ResponseEntity with status 200 (OK)
     */
    @DeleteMapping("/tb-activities/{id}")
    @Timed
    public ResponseEntity<Void> deleteTBActivity(@PathVariable Long id) {
        log.debug("REST request to delete TBActivity : {}", id);
        tBActivityService.delete(id);
        return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, id.toString())).build();
    }

    /**
     * SEARCH  /_search/tb-activities?query=:query : search for the tBActivity corresponding
     * to the query.
     *
     * @param query    the query of the tBActivity search
     * @param pageable the pagination information
     * @return the result of the search
     */
    @GetMapping("/_search/tb-activities")
    @Timed
    public ResponseEntity<List<TBActivityDTO>> searchTBActivities(@RequestParam String query, Pageable pageable) {
        log.debug("REST request to search for a page of TBActivities for query {}", query);
        Page<TBActivityDTO> page = tBActivityService.search(query, pageable);
        HttpHeaders headers = PaginationUtil.generateSearchPaginationHttpHeaders(query, page, "/api/_search/tb-activities");
        return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
    }

    private TBCommonActivityDTO parseTBCommonActivityDTOFromJsonString(String data_request) {
        TBCommonActivityDTO data;
        try {
            data = this.objectMapper.readValue(data_request, TBCommonActivityDTO.class);
        } catch (Exception e) {
            throw new BadRequestAlertException("1047", ENTITY_NAME, "1047");
        }
        return data;
    }

    @PostMapping("/create-common-activity/{activityTypeName}")
    @Transactional(readOnly = false)
    public ResponseEntity<Long> createCommonActivity(@PathVariable String activityTypeName,
                                                                    @RequestParam("tbCommonActivityDTO") String strTBCommonActivityDTO,
                                                                    @RequestParam(value = "images") final MultipartFile[] images) throws URISyntaxException {
        UserDTO userDTO = userService.getCurrentUserDTO().get();
        TBCommonActivityDTO tbCommonActivityDTO = parseTBCommonActivityDTOFromJsonString(strTBCommonActivityDTO);
        TBActivityTypeDTO tbActivityTypeDTO = tbActivityTypeService.findOne(tbCommonActivityDTO.getTbActivityTypeId()).get();
        if(!tbActivityTypeDTO.getName().equals(activityTypeName)){
            throw new ForbiddenException();
        }
        //Save activity
        TBActivityDTO tbActivityDTO = new TBActivityDTO();
        tbActivityDTO.setActivityTypeId(tbCommonActivityDTO.getTbActivityTypeId());
        tbActivityDTO.setCropId(tbCommonActivityDTO.getTbCropId());
        tbActivityDTO.setExecuteDate(Instant.now());
        if(tbCommonActivityDTO.getExecuteDate() != null) {
            tbActivityDTO.setExecuteDate(tbCommonActivityDTO.getExecuteDate());
        }
        tbActivityDTO.setTotalCost(tbCommonActivityDTO.getTotalCost());
        tbActivityDTO.setExternalTable(tbCommonActivityDTO.getExternalTable());
        tbActivityDTO.setDescription(tbCommonActivityDTO.getDescription());
        tbActivityDTO.setCreatedDate(Instant.now());
        tbActivityDTO.setCreatedById(userDTO.getUserId());
        Integer ageDay = tBCropQueryService.getAgeDayByCropID(tbCommonActivityDTO.getTbCropId(), tbActivityDTO.getExecuteDate());
        tbActivityDTO.setAgeDay(ageDay);
        tbActivityDTO = tBActivityQueryService.saveUploadedFiles(tbActivityDTO, images, tbActivityTypeDTO.getName());
        TBActivityDTO result = tBActivityService.save(tbActivityDTO);

        //update start_date
        if (this.checkExistedPlantingAndNursery(tbCommonActivityDTO.getTbCropId(), activityTypeName)){
            TBCropDTO currentCropDTO = tbCropService.findOne(tbCommonActivityDTO.getTbCropId()).get();
            currentCropDTO.setStartDate(result.getCreatedDate());
            TBCropDTO updatedCropDTO = tbCropService.save(currentCropDTO);
        }
        //Update status crop
        if(tbActivityTypeDTO.getName().equals(Constants.ACTIVE_TYPE_END)) {
            TBCropDTO tbCropDto = tbCropService.findOne(tbCommonActivityDTO.getTbCropId()).get();
            tbCropDto.setStatus(Constants.ENUM_CROP_STATUS.STATUS_FINISHED.name());
            tbCropDto.setEndDate(Instant.now());
            tbCropService.save(tbCropDto);
        }
        //Save list object update
        if(tbCommonActivityDTO.getTbObjectUpdateDTOList() != null
            && tbCommonActivityDTO.getTbObjectUpdateDTOList().size() > 0) {
            for (TBObjectUpdateDTO objectUpdateDTO : tbCommonActivityDTO.getTbObjectUpdateDTOList()) {
                objectUpdateDTO.setTbActivityId(result.getId());
                tbObjectUpdateService.save(objectUpdateDTO);
            }
        }

        //Save list tb_nursery_details
        if(tbCommonActivityDTO.getTbNurseryDetailsDTOList() != null
            && tbCommonActivityDTO.getTbNurseryDetailsDTOList().size() > 0) {
            for (TBNurseryDetailsDTO tbNurseryDetailsDTO : tbCommonActivityDTO.getTbNurseryDetailsDTOList()) {
                tbNurseryDetailsDTO.setTbActivityId(result.getId());
                tbNurseryDetailsService.save(tbNurseryDetailsDTO);
            }
        }

        //Save list tb_supplies_using_details
        if(tbCommonActivityDTO.getTbSuppliesUsingDetailsDTOs() != null
            && tbCommonActivityDTO.getTbSuppliesUsingDetailsDTOs().size() > 0) {
            for (TBSuppliesUsingDetailsDTO tbSuppliesUsingDetailsDTO : tbCommonActivityDTO.getTbSuppliesUsingDetailsDTOs()) {

                //Get tbSuppliesInWarehouse by id
                TBSuppliesInWarehouseDTO tbSuppliesInWarehouseDTO = tbSuppliesInWarehouseService.findOne(tbSuppliesUsingDetailsDTO.getTbSuppliesInWarehouseId()).get();

                //Save TBSuppliesUsingDetails
                tbSuppliesUsingDetailsDTO.setTbActivityId(result.getId());
                tbSuppliesUsingDetailsService.save(tbSuppliesUsingDetailsDTO);

                //Save TBStockUpdate
                TBStockUpdateDTO tbStockUpdateDTO = new TBStockUpdateDTO();
                tbStockUpdateDTO.setUpdateDate(Instant.now());
                tbStockUpdateDTO.setAction(Constants.STOCK_UPDATE_ACTION.EXPORT.getValue());
                tbStockUpdateDTO.setQuantity(tbSuppliesUsingDetailsDTO.getQuantity());
                tbStockUpdateDTO.setTbSuppliesInWarehouseId(tbSuppliesInWarehouseDTO.getId());
                tbStockUpdateDTO.setTbBlockDetailsId(tbSuppliesUsingDetailsDTO.getTbBlockDetailsId());
                tbStockUpdateDTO.setTbActivityId(result.getId());
                tbStockUpdateService.save(tbStockUpdateDTO);

                //Update quantity tbBlockDetails
                TBBlockDetailsDTO tbBlockDetailsDTO = tbBlockDetailsService.findOne(tbSuppliesUsingDetailsDTO.getTbBlockDetailsId()).get();
                Double exportBlockDetailsQuantity = tbBlockDetailsDTO.getQuantity()-tbStockUpdateDTO.getQuantity();
                if(exportBlockDetailsQuantity < 0) {
                    throw new BadRequestAlertException("1059", ENTITY_NAME, "1059");
                }
                tbBlockDetailsDTO.setQuantity(exportBlockDetailsQuantity);
                tbBlockDetailsService.save(tbBlockDetailsDTO);

                //Update quantity tbSuppliesInWarehouse
                Double exportSuppliesInWarehouseQuantity = tbSuppliesInWarehouseDTO.getQuantity()-tbStockUpdateDTO.getQuantity();
                if(exportBlockDetailsQuantity < 0) {
                    throw new BadRequestAlertException("1060", ENTITY_NAME, "1060");
                }
                tbSuppliesInWarehouseDTO.setQuantity(exportSuppliesInWarehouseQuantity);
                tbSuppliesInWarehouseService.save(tbSuppliesInWarehouseDTO);
            }
        }
        return ResponseEntity.ok().body(result.getId());
    }

    private boolean checkExistedPlantingAndNursery(Long cropId, String activityTypeName) {
        TBCropDTO tbCropDTO = tbCropService.findOne(cropId).get();
        if (!activityTypeName.equals("ACTIVE_TYPE_NURSERY") && !activityTypeName.equals("ACTIVE_TYPE_PLANTING")) {
            return false;
        }
        // Get list of activity
        TBActivityCriteria criteria = new TBActivityCriteria();
        LongFilter cropFilter = new LongFilter();
        cropFilter.setEquals(cropId);
        criteria.setCropId(cropFilter);
        List<TBActivityDTO> allActivities = tBActivityQueryService.findByCriteria(criteria);
        //1: Lo Uom - 2: Lo Trong
        if ((tbCropDTO.getTbCropTypeId() == 1 && activityTypeName.equals("ACTIVE_TYPE_NURSERY"))
            || (tbCropDTO.getTbCropTypeId() == 2 && activityTypeName.equals("ACTIVE_TYPE_PLANTING"))) {
            allActivities = allActivities.stream()
                .filter(activity -> activityTypeName.equals(activity.getActivityTypeName()))
                .collect(Collectors.toList());
            return allActivities.size() <= 0;
        }
        return false;
    }

    @GetMapping("/get-detail-common-activity/{activityTypeName}/{tbActivityId}")
    public ResponseEntity<TBCommonActivityDTO> getDetailCommonActivity(@PathVariable String activityTypeName,
                                                                       @PathVariable Long tbActivityId) throws URISyntaxException {
        TBCommonActivityDTO tbCommonActivityDTO = new TBCommonActivityDTO();
        TBActivityDTO tbActivityDTO = tbActivityService.findOne(tbActivityId).get();
        if(!userRoleUtil.currentUserHasPermissionByCropId(tbActivityDTO.getCropId())){
            throw new BadRequestAlertException("1018", ENTITY_NAME, "1018");
        }
        TBActivityTypeDTO tbActivityTypeDTO = tbActivityTypeService.findOne(tbActivityDTO.getActivityTypeId()).get();
        if(!tbActivityTypeDTO.getName().equals(activityTypeName)){
            throw new ForbiddenException();
        }

        // Get TBActivity
        tbCommonActivityDTO.setId(tbActivityId);
        tbCommonActivityDTO.setTbActivityTypeId(tbActivityDTO.getActivityTypeId());
        tbCommonActivityDTO.setTbCropId(tbActivityDTO.getCropId());
        tbCommonActivityDTO.setTotalCost(tbActivityDTO.getTotalCost());
        tbCommonActivityDTO.setMedia(tbActivityDTO.getMedia());
        tbCommonActivityDTO.setExecuteDate(tbActivityDTO.getExecuteDate());
        tbCommonActivityDTO.setExternalTable(tbActivityDTO.getExternalTable());
        tbCommonActivityDTO.setDescription(tbActivityDTO.getDescription());
        tbCommonActivityDTO.setExecuteBy(tbActivityDTO.getCreatedByName());

        // Get TBNurseryDetails by tbActivityId
        TBNurseryDetailsCriteria tbNurseryDetailsCriteria = new TBNurseryDetailsCriteria();
        LongFilter activityFilter = new LongFilter();
        activityFilter.setEquals(tbActivityId);
        tbNurseryDetailsCriteria.setTbActivityId(activityFilter);
        List<TBNurseryDetailsDTO> tbNurseryDetailsDTOs = tbNurseryDetailsQueryService.findByCriteria(tbNurseryDetailsCriteria);
        tbCommonActivityDTO.setTbNurseryDetailsDTOList(tbNurseryDetailsDTOs);

        // Get TBSuppliesUsingDetails by tbActivityId
        TBSuppliesUsingDetailsCriteria tbSuppliesUsingDetailsCriteria = new TBSuppliesUsingDetailsCriteria();
        tbSuppliesUsingDetailsCriteria.setTbActivityId(activityFilter);
        List<TBSuppliesUsingDetailsDTO> tbSuppliesUsingDetailsDTOs = tbSuppliesUsingDetailsQueryService.findByCriteria(tbSuppliesUsingDetailsCriteria);
        tbCommonActivityDTO.setTbSuppliesUsingDetailsDTOs(tbSuppliesUsingDetailsDTOs);

        // Get TBEnvironmentUpdate by tbActivityId
        ActivityEnvironmentUpdateDTO activityEnvironmentUpdateDTO = tBEnvironmentUpdateQueryService.getEnvironmentUpdateActivity(tbActivityId).get();
        tbCommonActivityDTO.setTbEnvironmentUpdateDTOList(activityEnvironmentUpdateDTO.getEnvironmentUpdates());

        // Get TBObjectUpdate by tbActivityId
        TBObjectUpdateCriteria tbObjectUpdateCriteria = new TBObjectUpdateCriteria();
        tbObjectUpdateCriteria.setTbActivityId(activityFilter);
        List<TBObjectUpdateDTO> finalTBObjectUpdateDTOs = new ArrayList<>();
        List<TBObjectUpdateDTO> tbObjectUpdateDTOs = tbObjectUpdateQueryService.findByCriteria(tbObjectUpdateCriteria);
        for(TBObjectUpdateDTO tbObjectUpdateDTO : tbObjectUpdateDTOs) {
            TBObjectParameterDTO tbObjectParameterDTO = tbObjectUpdateDTO.getTbObjectParameterDTO();
            List<TBActivityExtendTypeDropDownDTO> tbActivityExtendTypeDropDownDTOs;

            // Get list data common from table by condition
            if(tbObjectParameterDTO.getTbActivityExtendTypeCondition() != null) {
                tbActivityExtendTypeDropDownDTOs = tbObjectParameterQueryService.getDataFromTableCommon(
                    tbObjectParameterDTO.getTbActivityExtendTypeExternalTable(),
                    tbObjectParameterDTO.getTbActivityExtendTypeCondition());

            // Get list data common from table by condition
            } else if (tbObjectParameterDTO.getTbActivityExtendTypeExternalTable() != null) {
                tbActivityExtendTypeDropDownDTOs = tbObjectParameterQueryService.getAllDataFromTableCommon(
                    tbObjectParameterDTO.getTbActivityExtendTypeExternalTable());
            }

            // other control type
            else {
                tbActivityExtendTypeDropDownDTOs = new ArrayList<>();
            }
            tbObjectParameterDTO.setTbActivityExtendTypeDropDownDTOList(tbActivityExtendTypeDropDownDTOs);
            tbObjectUpdateDTO.setTbObjectParameterDTO(tbObjectParameterDTO);
            finalTBObjectUpdateDTOs.add(tbObjectUpdateDTO);
        }
        tbCommonActivityDTO.setTbObjectUpdateDTOList(finalTBObjectUpdateDTOs);
        return ResponseEntity.ok().body(tbCommonActivityDTO);
    }

    @PostMapping("/update-common-activity/{activityTypeName}")
    @Transactional(readOnly = false)
    public ResponseEntity<Long> updateCommonActivity(@PathVariable String activityTypeName,
                                                                    @RequestParam("tbCommonActivityDTO") String strTBCommonActivityDTO,
                                                                    @RequestParam(value = "images") final MultipartFile[] images) throws URISyntaxException {
        TBCommonActivityDTO tbCommonActivityDTO = parseTBCommonActivityDTOFromJsonString(strTBCommonActivityDTO);
        TBActivityTypeDTO tbActivityTypeDTO = tbActivityTypeService.findOne(tbCommonActivityDTO.getTbActivityTypeId()).get();
        if(!tbActivityTypeDTO.getName().equals(activityTypeName)){
            throw new ForbiddenException();
        }
        //Update activity
        TBActivityDTO tbActivityDTO = tBActivityService.findOne(tbCommonActivityDTO.getId()).get();
        if(!userRoleUtil.currentUserHasPermissionByCropId(tbActivityDTO.getCropId())){
            throw new BadRequestAlertException("1018", ENTITY_NAME, "1018");
        }
        tbActivityDTO.setActivityTypeId(tbCommonActivityDTO.getTbActivityTypeId());
        tbActivityDTO.setCropId(tbCommonActivityDTO.getTbCropId());
        tbActivityDTO.setTotalCost(tbCommonActivityDTO.getTotalCost());
        tbActivityDTO.setMedia(tbCommonActivityDTO.getMedia());
        tbActivityDTO.setExternalTable(tbCommonActivityDTO.getExternalTable());
        tbActivityDTO.setDescription(tbCommonActivityDTO.getDescription());
        Integer ageDay = tBCropQueryService.getAgeDayByCropID(tbCommonActivityDTO.getTbCropId(),
                                                                tbCommonActivityDTO.getExecuteDate());
        tbActivityDTO.setAgeDay(ageDay);

        //Update upload files
        tbActivityDTO = tBActivityQueryService.updateUploadedFiles(tbActivityDTO,
                                                                    images,
                                                                    tbActivityTypeDTO.getName(),
                                                                    tbCommonActivityDTO.getDeletedImages());
        TBActivityDTO result = tBActivityService.save(tbActivityDTO);

        //Update status crop
        if(tbActivityTypeDTO.getName().equals(Constants.ACTIVE_TYPE_END)) {
            TBCropDTO tbCropDto = tbCropService.findOne(tbCommonActivityDTO.getTbCropId()).get();
            tbCropDto.setStatus(Constants.ENUM_CROP_STATUS.STATUS_FINISHED.name());
            tbCropDto.setEndDate(Instant.now());
            tbCropService.save(tbCropDto);
        }

        //Update list object update
        if(tbCommonActivityDTO.getTbObjectUpdateDTOList() != null
            && tbCommonActivityDTO.getTbObjectUpdateDTOList().size() > 0) {
            for (TBObjectUpdateDTO objectUpdateDTO : tbCommonActivityDTO.getTbObjectUpdateDTOList()) {
                TBObjectUpdateDTO updatedTBObjectUpdateDTO = tbObjectUpdateService.findOne(objectUpdateDTO.getId()).get();
                updatedTBObjectUpdateDTO.setIndex(objectUpdateDTO.getIndex());
                updatedTBObjectUpdateDTO.setTbActivityId(result.getId());
                tbObjectUpdateService.save(updatedTBObjectUpdateDTO);
            }
        }

        // Delete TBNurseryDetails by tbActivityId
        TBNurseryDetailsCriteria tbNurseryDetailsCriteria = new TBNurseryDetailsCriteria();
        LongFilter activityFilter = new LongFilter();
        activityFilter.setEquals(result.getId());
        tbNurseryDetailsCriteria.setTbActivityId(activityFilter);
        List<TBNurseryDetailsDTO> tbNurseryDetailsDTOs = tbNurseryDetailsQueryService.findByCriteria(tbNurseryDetailsCriteria);
        if(tbNurseryDetailsDTOs.size() > 0) {
            for(TBNurseryDetailsDTO tbNurseryDetailsDTO : tbNurseryDetailsDTOs) {
                tbNurseryDetailsService.delete(tbNurseryDetailsDTO.getId());
            }
        }

        //Create list tb_nursery_details
        if(tbCommonActivityDTO.getTbNurseryDetailsDTOList() != null
            && tbCommonActivityDTO.getTbNurseryDetailsDTOList().size() > 0) {
            for (TBNurseryDetailsDTO tbNurseryDetailsDTO : tbCommonActivityDTO.getTbNurseryDetailsDTOList()) {
                tbNurseryDetailsDTO.setTbActivityId(result.getId());
                tbNurseryDetailsService.save(tbNurseryDetailsDTO);
            }
        }

        // Delete TBSuppliesUsingDetails by tbActivityId
        TBSuppliesUsingDetailsCriteria tbSuppliesUsingDetailsCriteria = new TBSuppliesUsingDetailsCriteria();
        tbSuppliesUsingDetailsCriteria.setTbActivityId(activityFilter);
        List<TBSuppliesUsingDetailsDTO> tbSuppliesUsingDetailsDTOs = tbSuppliesUsingDetailsQueryService.findByCriteria(tbSuppliesUsingDetailsCriteria);
        if(tbSuppliesUsingDetailsDTOs.size() > 0) {
            for(TBSuppliesUsingDetailsDTO tbSuppliesUsingDetailsDTO : tbSuppliesUsingDetailsDTOs) {
                tbSuppliesUsingDetailsService.delete(tbSuppliesUsingDetailsDTO.getId());
            }
        }
        // Delete TBStockUpdate by tbActivityId
        TBStockUpdateCriteria tbStockUpdateCriteria = new TBStockUpdateCriteria();
        tbStockUpdateCriteria.setTbActivityId(activityFilter);
        List<TBStockUpdateDTO> tbStockUpdateDTOs = tbStockUpdateQueryService.findByCriteria(tbStockUpdateCriteria);
        if(tbStockUpdateDTOs.size() > 0) {
            for(TBStockUpdateDTO tbStockUpdateDTO : tbStockUpdateDTOs) {

                //Update quantity tbBlockDetails
                TBBlockDetailsDTO tbBlockDetailsDTO = tbBlockDetailsService.findOne(tbStockUpdateDTO.getTbBlockDetailsId()).get();
                Double importBlockDetailsQuantity = tbBlockDetailsDTO.getQuantity() + tbStockUpdateDTO.getQuantity();
                if(importBlockDetailsQuantity < 0) {
                    throw new BadRequestAlertException("1059", ENTITY_NAME, "1059");
                }
                tbBlockDetailsDTO.setQuantity(importBlockDetailsQuantity);
                tbBlockDetailsService.save(tbBlockDetailsDTO);

                //Update quantity tbSuppliesInWarehouse
                TBSuppliesInWarehouseDTO tbSuppliesInWarehouseDTO = tbSuppliesInWarehouseService.findOne(tbStockUpdateDTO.getTbSuppliesInWarehouseId()).get();
                Double importSuppliesInWarehouseQuantity = tbSuppliesInWarehouseDTO.getQuantity() + tbStockUpdateDTO.getQuantity();
                if(importSuppliesInWarehouseQuantity < 0) {
                    throw new BadRequestAlertException("1060", ENTITY_NAME, "1060");
                }
                tbSuppliesInWarehouseDTO.setQuantity(importSuppliesInWarehouseQuantity);
                tbSuppliesInWarehouseService.save(tbSuppliesInWarehouseDTO);

                tbStockUpdateService.delete(tbStockUpdateDTO.getId());
            }
        }

        //Create list tb_supplies_using_details
        if(tbCommonActivityDTO.getTbSuppliesUsingDetailsDTOs() != null
            && tbCommonActivityDTO.getTbSuppliesUsingDetailsDTOs().size() > 0) {
            for (TBSuppliesUsingDetailsDTO tbSuppliesUsingDetailsDTO : tbCommonActivityDTO.getTbSuppliesUsingDetailsDTOs()) {

                //Get tbSuppliesInWarehouse by suppliesId and warehouseId
                TBSuppliesInWarehouseDTO tbSuppliesInWarehouseDTO = tbSuppliesInWarehouseService.findOne(tbSuppliesUsingDetailsDTO.getTbSuppliesInWarehouseId()).get();

                //Save TBSuppliesUsingDetails
                tbSuppliesUsingDetailsDTO.setTbActivityId(result.getId());
                tbSuppliesUsingDetailsService.save(tbSuppliesUsingDetailsDTO);

                //Save TBStockUpdate
                TBStockUpdateDTO tbStockUpdateDTO = new TBStockUpdateDTO();
                tbStockUpdateDTO.setUpdateDate(Instant.now());
                tbStockUpdateDTO.setAction(Constants.STOCK_UPDATE_ACTION.EXPORT.getValue());
                tbStockUpdateDTO.setQuantity(tbSuppliesUsingDetailsDTO.getQuantity());
                tbStockUpdateDTO.setTbSuppliesInWarehouseId(tbSuppliesInWarehouseDTO.getId());
                tbStockUpdateDTO.setTbBlockDetailsId(tbSuppliesUsingDetailsDTO.getTbBlockDetailsId());
                tbStockUpdateDTO.setTbActivityId(result.getId());
                tbStockUpdateService.save(tbStockUpdateDTO);

                //Update quantity tbBlockDetails
                TBBlockDetailsDTO tbBlockDetailsDTO = tbBlockDetailsService.findOne(tbSuppliesUsingDetailsDTO.getTbBlockDetailsId()).get();
                Double exportBlockDetailsQuantity = tbBlockDetailsDTO.getQuantity()-tbStockUpdateDTO.getQuantity();
                if(exportBlockDetailsQuantity < 0) {
                    throw new BadRequestAlertException("1059", ENTITY_NAME, "1059");
                }
                tbBlockDetailsDTO.setQuantity(exportBlockDetailsQuantity);
                tbBlockDetailsService.save(tbBlockDetailsDTO);

                //Update quantity tbSuppliesInWarehouse
                Double exportSuppliesInWarehouseQuantity = tbSuppliesInWarehouseDTO.getQuantity()-tbStockUpdateDTO.getQuantity();
                if(exportBlockDetailsQuantity < 0) {
                    throw new BadRequestAlertException("1060", ENTITY_NAME, "1060");
                }
                tbSuppliesInWarehouseDTO.setQuantity(exportSuppliesInWarehouseQuantity);
                tbSuppliesInWarehouseService.save(tbSuppliesInWarehouseDTO);
            }
        }
        return ResponseEntity.ok().body(result.getId());
    }

    @DeleteMapping("/delete-common-activity/{activityTypeName}/{tbActivityId}")
    @Transactional(readOnly = false)
    public ResponseEntity<Long> deleteCommonActivity(@PathVariable String activityTypeName, @PathVariable Long tbActivityId) throws URISyntaxException {
        TBActivityDTO tbActivityDTO = tbActivityService.findOne(tbActivityId).get();
        if(!tbActivityDTO.getActivityTypeName().equals(activityTypeName)){
            throw new ForbiddenException();
        }
        if(!userRoleUtil.currentUserHasPermissionByCropId(tbActivityDTO.getCropId())){
            throw new BadRequestAlertException("1018", ENTITY_NAME, "1018");
        }

        // Delete TBNurseryDetails by tbActivityId
        TBNurseryDetailsCriteria tbNurseryDetailsCriteria = new TBNurseryDetailsCriteria();
        LongFilter activityFilter = new LongFilter();
        activityFilter.setEquals(tbActivityId);
        tbNurseryDetailsCriteria.setTbActivityId(activityFilter);
        List<TBNurseryDetailsDTO> tbNurseryDetailsDTOs = tbNurseryDetailsQueryService.findByCriteria(tbNurseryDetailsCriteria);
        if(tbNurseryDetailsDTOs.size() > 0) {
            for(TBNurseryDetailsDTO tbNurseryDetailsDTO : tbNurseryDetailsDTOs) {
                tbNurseryDetailsService.delete(tbNurseryDetailsDTO.getId());
            }
        }


        // Delete TBSuppliesUsingDetails by tbActivityId
        TBSuppliesUsingDetailsCriteria tbSuppliesUsingDetailsCriteria = new TBSuppliesUsingDetailsCriteria();
        tbSuppliesUsingDetailsCriteria.setTbActivityId(activityFilter);
        List<TBSuppliesUsingDetailsDTO> tbSuppliesUsingDetailsDTOs = tbSuppliesUsingDetailsQueryService.findByCriteria(tbSuppliesUsingDetailsCriteria);
        if(tbSuppliesUsingDetailsDTOs.size() > 0) {
            for(TBSuppliesUsingDetailsDTO tbSuppliesUsingDetailsDTO : tbSuppliesUsingDetailsDTOs) {
                tbSuppliesUsingDetailsService.delete(tbSuppliesUsingDetailsDTO.getId());
            }
        }

        // Delete TBStockUpdate by tbActivityId
        TBStockUpdateCriteria tbStockUpdateCriteria = new TBStockUpdateCriteria();
        tbStockUpdateCriteria.setTbActivityId(activityFilter);
        List<TBStockUpdateDTO> tbStockUpdateDTOs = tbStockUpdateQueryService.findByCriteria(tbStockUpdateCriteria);
        if(tbStockUpdateDTOs.size() > 0) {
            for(TBStockUpdateDTO tbStockUpdateDTO : tbStockUpdateDTOs) {

                //Update quantity tbBlockDetails
                TBBlockDetailsDTO tbBlockDetailsDTO = tbBlockDetailsService.findOne(tbStockUpdateDTO.getTbBlockDetailsId()).get();
                Double importBlockDetailsQuantity = tbBlockDetailsDTO.getQuantity() + tbStockUpdateDTO.getQuantity();
                if(importBlockDetailsQuantity < 0) {
                    throw new BadRequestAlertException("1059", ENTITY_NAME, "1059");
                }
                tbBlockDetailsDTO.setQuantity(importBlockDetailsQuantity);
                tbBlockDetailsService.save(tbBlockDetailsDTO);

                //Update quantity tbSuppliesInWarehouse
                TBSuppliesInWarehouseDTO tbSuppliesInWarehouseDTO = tbSuppliesInWarehouseService.findOne(tbStockUpdateDTO.getTbSuppliesInWarehouseId()).get();
                Double importSuppliesInWarehouseQuantity = tbSuppliesInWarehouseDTO.getQuantity() + tbStockUpdateDTO.getQuantity();
                if(importSuppliesInWarehouseQuantity < 0) {
                    throw new BadRequestAlertException("1060", ENTITY_NAME, "1060");
                }
                tbSuppliesInWarehouseDTO.setQuantity(importSuppliesInWarehouseQuantity);
                tbSuppliesInWarehouseService.save(tbSuppliesInWarehouseDTO);

                tbStockUpdateService.delete(tbStockUpdateDTO.getId());
            }
        }

        // Delete TBObjectUpdate by tbActivityId
        TBObjectUpdateCriteria tbObjectUpdateCriteria = new TBObjectUpdateCriteria();
        tbObjectUpdateCriteria.setTbActivityId(activityFilter);
        List<TBObjectUpdateDTO> tbObjectUpdateDTOs = tbObjectUpdateQueryService.findByCriteria(tbObjectUpdateCriteria);
        if(tbObjectUpdateDTOs.size() > 0) {
            for(TBObjectUpdateDTO tbObjectUpdateDTO : tbObjectUpdateDTOs) {
                tbObjectUpdateService.delete(tbObjectUpdateDTO.getId());
            }
        }
        // Delete TBActivity
        tBActivityService.delete(tbActivityId);

        return ResponseEntity.ok().body(tbActivityId);
    }
}
