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 vn.azteam.tpf.domain.TBBlockDetails;
import vn.azteam.tpf.service.TBSuppliesInWarehouseService;
import vn.azteam.tpf.service.TBSuppliesService;
import vn.azteam.tpf.service.dto.*;
import vn.azteam.tpf.web.rest.errors.BadRequestAlertException;
import vn.azteam.tpf.web.rest.util.HeaderUtil;
import vn.azteam.tpf.web.rest.util.PaginationUtil;
import vn.azteam.tpf.Constants.Constants;
import vn.azteam.tpf.service.TBBlockDetailsQueryService;
import vn.azteam.tpf.service.TBSuppliesInWarehouseQueryService;
import vn.azteam.tpf.service.UserService;
import vn.azteam.tpf.service.TBSuppliesService;
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 java.net.URI;
import java.net.URISyntaxException;

import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.stream.StreamSupport;

import javax.validation.Valid;

import static org.elasticsearch.index.query.QueryBuilders.*;

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

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

    private static final String ENTITY_NAME = "tBSuppliesInWarehouse";

    private final TBSuppliesInWarehouseService tBSuppliesInWarehouseService;

    private final UserService userService;

    private final TBSuppliesService tBSuppliesService;

    private final TBSuppliesInWarehouseQueryService tBSuppliesInWarehouseQueryService;

    private final TBBlockDetailsQueryService tBlockDetailsQueryService;

    public TBSuppliesInWarehouseResource(TBSuppliesInWarehouseService tBSuppliesInWarehouseService,
                                         UserService userService,
                                         TBSuppliesService tBSuppliesService,
                                         TBSuppliesInWarehouseQueryService tBSuppliesInWarehouseQueryService,
                                         TBBlockDetailsQueryService tBlockDetailsQueryService) {
        this.tBSuppliesInWarehouseService = tBSuppliesInWarehouseService;
        this.userService = userService;
        this.tBSuppliesService = tBSuppliesService;
        this.tBSuppliesInWarehouseQueryService = tBSuppliesInWarehouseQueryService;
        this.tBlockDetailsQueryService = tBlockDetailsQueryService;
    }

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

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

    /**
     * GET  /tb-supplies-in-warehouses : get all the tBSuppliesInWarehouses.
     *
     * @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 tBSuppliesInWarehouses in body
     */
    @GetMapping("/tb-supplies-in-warehouses")
    @Timed
    public ResponseEntity<List<TBSuppliesInWarehouseDTO>> getAllTBSuppliesInWarehouses(TBSuppliesInWarehouseCriteria criteria, Pageable pageable) {
        log.debug("REST request to get TBSuppliesInWarehouses by criteria: {}", criteria);
        Page<TBSuppliesInWarehouseDTO> page = tBSuppliesInWarehouseQueryService.findByCriteria(criteria, pageable);
        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/tb-supplies-in-warehouses");
        return ResponseEntity.ok().headers(headers).body(page.getContent());
    }

    /**
    * GET  /tb-supplies-in-warehouses/count : count all the tBSuppliesInWarehouses.
    *
    * @param criteria the criterias which the requested entities should match
    * @return the ResponseEntity with status 200 (OK) and the count in body
    */
    @GetMapping("/tb-supplies-in-warehouses/count")
    @Timed
    public ResponseEntity<Long> countTBSuppliesInWarehouses(TBSuppliesInWarehouseCriteria criteria) {
        log.debug("REST request to count TBSuppliesInWarehouses by criteria: {}", criteria);
        return ResponseEntity.ok().body(tBSuppliesInWarehouseQueryService.countByCriteria(criteria));
    }

    /**
     * GET  /tb-supplies-in-warehouses/:id : get the "id" tBSuppliesInWarehouse.
     *
     * @param id the id of the tBSuppliesInWarehouseDTO to retrieve
     * @return the ResponseEntity with status 200 (OK) and with body the tBSuppliesInWarehouseDTO, or with status 404 (Not Found)
     */
    @GetMapping("/tb-supplies-in-warehouses/{id}")
    @Timed
    public ResponseEntity<TBSuppliesInWarehouseDTO> getTBSuppliesInWarehouse(@PathVariable Long id) {
        log.debug("REST request to get TBSuppliesInWarehouse : {}", id);
        Optional<TBSuppliesInWarehouseDTO> tBSuppliesInWarehouseDTO = tBSuppliesInWarehouseService.findOne(id);
        return ResponseUtil.wrapOrNotFound(tBSuppliesInWarehouseDTO);
    }

    /**
     * DELETE  /tb-supplies-in-warehouses/:id : delete the "id" tBSuppliesInWarehouse.
     *
     * @param id the id of the tBSuppliesInWarehouseDTO to delete
     * @return the ResponseEntity with status 200 (OK)
     */
    @DeleteMapping("/tb-supplies-in-warehouses/{id}")
    @Timed
    public ResponseEntity<Void> deleteTBSuppliesInWarehouse(@PathVariable Long id) {
        log.debug("REST request to delete TBSuppliesInWarehouse : {}", id);
        UserDTO currentUserDTO = userService.getCurrentUserDTO().get();
        TBSuppliesDTO currentSuppliseDTO = tBSuppliesService.findOne(id).get();
        if(currentUserDTO.getCustomerId() != null && !currentUserDTO.getCustomerId().equals(currentSuppliseDTO.getTbCustomerId())){
            throw new BadRequestAlertException("1056", ENTITY_NAME, "1056");
        }
        tBSuppliesInWarehouseService.delete(id);
        return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, id.toString())).build();
    }

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

    @PostMapping("/createTBSuppliesInWarehouse")
    @Timed
    public ResponseEntity<TBSuppliesInWarehouseDTO> createWarehouseStockUpdate(@RequestBody @Valid WarehouseStockUpdateDTO warehouseStockUpdateDTO) throws URISyntaxException {
        log.debug("REST request to save WarehouseStockUpdateDTO : {}", warehouseStockUpdateDTO);
        validate(warehouseStockUpdateDTO);
        validateExistCodeBlockDetail(warehouseStockUpdateDTO.getTbWarehouseId()
                                    , warehouseStockUpdateDTO.getTbSuppliesId()
                                    , warehouseStockUpdateDTO.getCode());
        warehouseStockUpdateDTO.setUpdateDate(Instant.now());
        TBSuppliesInWarehouseDTO result = tBSuppliesInWarehouseQueryService.createWarehouseStockUpdate(warehouseStockUpdateDTO);
        return ResponseEntity.ok()
            .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, result.getId().toString()))
            .body(result);
    }

     /**
     * Validate Request Method DTOs: Create, Update
     * @param warehouseStockUpdateDTO
     */
    private void validate(@RequestBody WarehouseStockUpdateDTO warehouseStockUpdateDTO) {
        if (warehouseStockUpdateDTO.getId() != null) {
            throw new BadRequestAlertException("1010", ENTITY_NAME, "1010");
        }
        if (warehouseStockUpdateDTO.getTbSuppliesId() == null) {
            throw new BadRequestAlertException("1011", ENTITY_NAME, "1011");
        }
        if (warehouseStockUpdateDTO.getTbWarehouseId() == null) {
            throw new BadRequestAlertException("1012", ENTITY_NAME, "1012");
        }
        if (warehouseStockUpdateDTO.getQuantity() <= 0) {
            throw new BadRequestAlertException("1015", ENTITY_NAME, "1015");
        }
        //@CUONGLT - Filter scope customer's data
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        Optional<TBSuppliesDTO> suppliesDTO = tBSuppliesService.findOne(warehouseStockUpdateDTO.getTbSuppliesId());
        if (currentUser.getCustomerId() != null
            && suppliesDTO.get().getTbCustomerId() != null
            && currentUser.getCustomerId() != suppliesDTO.get().getTbCustomerId()){
            throw new BadRequestAlertException("1013", ENTITY_NAME, "1013");
        }
    }

    private void validateExistCodeBlockDetail(Long tbWarehouseId, Long tbSupplyId, String code) {
        TBSuppliesInWarehouseDTO tbSuppliesInWarehouseDTO = tBSuppliesInWarehouseQueryService.getTBSuppliesInWarehouseByWarehouseIdAndSupplyId(tbWarehouseId, tbSupplyId);
        TBBlockDetailsCriteria tbBlockDetailsCriteria = new TBBlockDetailsCriteria();
        StringFilter codeTBBlockDetail = new StringFilter();
        codeTBBlockDetail.setEquals(code);
        tbBlockDetailsCriteria.setCode(codeTBBlockDetail);
        List<TBBlockDetailsDTO> tbBlockDetailsDTOs = tBlockDetailsQueryService.findByCriteria(tbBlockDetailsCriteria);
        if(tbBlockDetailsDTOs != null
            && tbBlockDetailsDTOs.size() > 0
            && tbSuppliesInWarehouseDTO.getId() != tbBlockDetailsDTOs.get(0).getTbSuppliesInWarehouseId()) {
            throw new BadRequestAlertException("1055", ENTITY_NAME, "1055");
        }
    }

    @GetMapping("/detailSupplies/{id}")
    @Timed
    public ResponseEntity<TBSuppliesDetailDTO> getDetailSupplies(@PathVariable Long id) {
        TBSuppliesDetailDTO re = tBSuppliesInWarehouseQueryService.getDetailSupplies(id);
        return ResponseEntity.ok().body(re);
    }

    @GetMapping("/list-supplies-in-warehouses/{suppliesTypeName}")
    @Timed
    public ResponseEntity<List<TBSuppliesInWarehouseDTO>> getListTBSuppliesInWarehouses(@PathVariable String suppliesTypeName,
                                                                                        @RequestParam(value = "q", required=false) String q) {

        List<TBSuppliesInWarehouseDTO> result = tBSuppliesInWarehouseQueryService.getListTBSuppliesInWarehouses(suppliesTypeName, q);
        return ResponseEntity.ok().body(result);
    }

    @GetMapping("/list-supplies-in-warehouses-by-suppliesId/{suppliesId}")
    @Timed
    public ResponseEntity<List<TBSuppliesInWarehouseDTO>> getListTBSuppliesInWarehousesBySuppliesId(@PathVariable String suppliesId) {
        Long suppliesIdL;
        suppliesIdL = Long.parseLong(suppliesId);
        List<TBSuppliesInWarehouseDTO> result = tBSuppliesInWarehouseQueryService.getListTBSuppliesInWarehousesBySuppliesId(suppliesIdL);
        return ResponseEntity.ok().body(result);
    }

    @GetMapping("/seed-detail/{id}")
    @Timed
    public ResponseEntity<TBSuppliesDetailDTO> getSeedDetail(@PathVariable Long id) {
        Optional<TBSuppliesDetailDTO> detailSupplies = tBSuppliesInWarehouseQueryService.getSeedDetail(id);
        //@CUONGLT - Filter scope customer's data
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        Optional<TBSuppliesDTO> suppliesDTO = tBSuppliesService.findOne(id);

        if (currentUser.getCustomerId() != null
            && suppliesDTO.get().getTbCustomerId() != null
            && currentUser.getCustomerId() != suppliesDTO.get().getTbCustomerId()){
            throw new BadRequestAlertException("1013", ENTITY_NAME, "1013");
        }
        return ResponseUtil.wrapOrNotFound(detailSupplies);
    }
}
