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 org.springframework.data.domain.*;
import vn.azteam.tpf.service.*;
import vn.azteam.tpf.service.dto.*;
import vn.azteam.tpf.service.util.PageableUtil;
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 io.github.jhipster.web.util.ResponseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.Collectors;

import static vn.azteam.tpf.Constants.Constants.ENUM_SUPPLIES_TYPE.GIONG;

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

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

    private static final String ENTITY_NAME = "tBSupplies";

    private final TBSuppliesService tBSuppliesService;

    private final TBSuppliesTypeQueryService tBSuppliesTypeQueryService;

    private final TBSuppliesQueryService tBSuppliesQueryService;

    private final UserService userService;

    private final TBSuppliesTypeService tBSuppliesTypeService;

    private final PageableUtil pageableUtil;

    public TBSuppliesResource(
        TBSuppliesService tBSuppliesService,
        TBSuppliesQueryService tBSuppliesQueryService,
        TBSuppliesTypeQueryService tBSuppliesTypeQueryService,
        UserService userService,
        TBSuppliesTypeService tBSuppliesTypeService, PageableUtil pageableUtil) {
        this.tBSuppliesService = tBSuppliesService;
        this.tBSuppliesQueryService = tBSuppliesQueryService;
        this.tBSuppliesTypeQueryService = tBSuppliesTypeQueryService;
        this.userService = userService;
        this.tBSuppliesTypeService = tBSuppliesTypeService;
        this.pageableUtil = pageableUtil;
    }

    /**
     * POST  /tb-supplies : Create a new tBSupplies.
     *
     * @param tBSuppliesDTO the tBSuppliesDTO to create
     * @return the ResponseEntity with status 201 (Created) and with body the new tBSuppliesDTO, or with status 400 (Bad Request) if the tBSupplies has already an ID
     * @throws URISyntaxException if the Location URI syntax is incorrect
     */
    @PostMapping("/tb-supplies")
    @Timed
    public ResponseEntity<TBSuppliesDTO> createTBSupplies(@RequestBody TBSuppliesDTO tBSuppliesDTO) throws URISyntaxException {
        log.debug("REST request to save TBSupplies : {}", tBSuppliesDTO);
        if (tBSuppliesDTO.getId() != null) {
            throw new BadRequestAlertException("A new tBSupplies cannot already have an ID", ENTITY_NAME, "idexists");
        }
        if (tBSuppliesDTO.getTbSuppliesTypeId() == null) {
            throw new BadRequestAlertException("A new tbSuppliesTypeId cannot null", ENTITY_NAME, "not null");
        }
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        Optional<TBSuppliesDTO> suppliesDTO =
            tBSuppliesQueryService.findFirstBySkuAndCustomerId(
                tBSuppliesDTO.getSku(),
                currentUser.getCustomerId());
        if (suppliesDTO.isPresent()) {
            throw new BadRequestAlertException("Duplicate sku", ENTITY_NAME, "1017");
        }
        tBSuppliesDTO.setCreatedDate(Instant.now());
        tBSuppliesDTO.setCreatedById(currentUser.getId());
        tBSuppliesDTO.setTbCustomerId(tBSuppliesDTO.getTbCustomerId());
        if (currentUser.getCustomerId() != null) {
            tBSuppliesDTO.setTbCustomerId(currentUser.getCustomerId());
        }
        TBSuppliesDTO result = tBSuppliesService.save(tBSuppliesDTO);

        return ResponseEntity.created(new URI("/api/tb-supplies/" + result.getId()))
            .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
            .body(result);
    }

    @PostMapping("/tb-supplies/seed")
    @Timed
    public ResponseEntity<TBSuppliesDTO> createSeed(@RequestBody TBSuppliesDTO tBSuppliesDTO) throws URISyntaxException {
        if (tBSuppliesDTO.getName() == null) {
            throw new BadRequestAlertException("Invalid name", ENTITY_NAME, "namenull");
        }
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        Optional<TBSuppliesDTO> suppliesDTO =
            tBSuppliesQueryService.findFirstBySkuAndCustomerId(
                tBSuppliesDTO.getSku(),
                currentUser.getCustomerId());
        if (suppliesDTO.isPresent()) {
            throw new BadRequestAlertException("Duplicate sku", ENTITY_NAME, "1017");
        }
        setCustomerIdAndSupplyTypeId(tBSuppliesDTO);
        return createTBSupplies(tBSuppliesDTO);
    }

    /**
     * PUT  /tb-supplies : Updates an existing tBSupplies.
     *
     * @param tBSuppliesDTO the tBSuppliesDTO to update
     * @return the ResponseEntity with status 200 (OK) and with body the updated tBSuppliesDTO,
     * or with status 400 (Bad Request) if the tBSuppliesDTO is not valid,
     * or with status 500 (Internal Server Error) if the tBSuppliesDTO couldn't be updated
     * @throws URISyntaxException if the Location URI syntax is incorrect
     */
    @PutMapping("/tb-supplies")
    @Timed
    public ResponseEntity<TBSuppliesDTO> updateTBSupplies(@RequestBody TBSuppliesDTO tBSuppliesDTO) throws URISyntaxException {
        log.debug("REST request to update TBSupplies : {}", tBSuppliesDTO);
        if (tBSuppliesDTO.getId() == null) {
            throw new BadRequestAlertException("1011", ENTITY_NAME, "1011");
        }
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        Optional<TBSuppliesDTO> suppliesDTO =
            tBSuppliesQueryService.findFirstBySkuAndCustomerIdExceptId(
                tBSuppliesDTO.getSku(),
                tBSuppliesDTO.getId(),
                currentUser.getCustomerId());
        if (suppliesDTO.isPresent()) {
            throw new BadRequestAlertException("Duplicate sku", ENTITY_NAME, "1017");
        }
        TBSuppliesDTO old_tbSuppliesDTO = tBSuppliesService.findOne(tBSuppliesDTO.getId()).get();
        if (currentUser.getCustomerId() != null) {
            if(currentUser.getCustomerId() != old_tbSuppliesDTO.getTbCustomerId()){
                throw new BadRequestAlertException("1056", ENTITY_NAME, "1056");
            }
            tBSuppliesDTO.setTbCustomerId(currentUser.getCustomerId());
        }
        else {
            tBSuppliesDTO.setTbCustomerId(old_tbSuppliesDTO.getTbCustomerId());
        }
        tBSuppliesDTO.setCreatedById(old_tbSuppliesDTO.getCreatedById());
        tBSuppliesDTO.setCreatedDate(old_tbSuppliesDTO.getCreatedDate());
        tBSuppliesDTO.setModifiedDate(Instant.now());
        tBSuppliesDTO.setModifiedById(currentUser.getId());

        TBSuppliesDTO result = tBSuppliesService.save(tBSuppliesDTO);
        return ResponseEntity.ok()
            .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, tBSuppliesDTO.getId().toString()))
            .body(result);
    }

    @PutMapping("/tb-supplies/seed")
    @Timed
    public ResponseEntity<TBSuppliesDTO> updateSeed(@RequestBody TBSuppliesDTO tBSuppliesDTO) throws URISyntaxException {
        if (tBSuppliesDTO.getName() == null) {
            throw new BadRequestAlertException("Invalid name", ENTITY_NAME, "namenull");
        }
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        TBSuppliesDTO currentSuppliesDTO = tBSuppliesService.findOne(tBSuppliesDTO.getId()).get();
        if (tBSuppliesDTO.getId() != null) {
            Optional<TBSuppliesDTO> suppliesDTO =
                tBSuppliesQueryService.findFirstBySkuAndCustomerIdExceptId(
                    tBSuppliesDTO.getSku(),
                    tBSuppliesDTO.getId(),
                    currentUser.getCustomerId());
            if (suppliesDTO.isPresent()) {
                throw new BadRequestAlertException("Duplicate sku", ENTITY_NAME, "1017");
            }
            if (currentUser.getCustomerId() != null) {
                if(currentUser.getCustomerId() != currentSuppliesDTO.getTbCustomerId()){
                    throw new BadRequestAlertException("1056", ENTITY_NAME, "1056");
                }
                tBSuppliesDTO.setTbCustomerId(currentUser.getCustomerId());
            }
            else {
                tBSuppliesDTO.setTbCustomerId(currentSuppliesDTO.getTbCustomerId());
            }
        }

        return updateTBSupplies(tBSuppliesDTO);
    }

    private void setCustomerIdAndSupplyTypeId(@RequestBody TBSuppliesDTO tBSuppliesDTO) {
        UserDTO currentUser = userService.getCurrentUserDTO().get();

        if (currentUser.getCustomerId() != null) {
            tBSuppliesDTO.setTbCustomerId(currentUser.getCustomerId());
        }
        Optional<TBSuppliesTypeDTO> suppliesTypeDTO = tBSuppliesTypeService.findFirstByName(GIONG.name());
        if (!suppliesTypeDTO.isPresent()) {
            throw new BadRequestAlertException("Supply type GIONG not found", ENTITY_NAME, "1030");
        }
        tBSuppliesDTO.setTbSuppliesTypeId(suppliesTypeDTO.get().getId());
    }

    /**
     * GET  /tb-supplies : get all the tBSupplies.
     *
     * @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 tBSupplies in body
     */
    @GetMapping("/tb-supplies")
    @Timed
    public ResponseEntity<List<TBSuppliesDTO>> getAllTBSupplies(@RequestParam(value = "q", required = false) String q,
                                                                @RequestParam(value = "suppliesTypeId", required = false) Long suppliesTypeId,
                                                                TBSuppliesCriteria criteria, Pageable pageable) {
        log.debug("REST request to get TBSupplies by criteria: {}", criteria);
        Page<TBSuppliesDTO> page = tBSuppliesQueryService.getListTBSuppliesToCustomer(criteria, pageable, q, suppliesTypeId);
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        if (currentUser.getCustomerId() != null) {
            List<TBSuppliesDTO> tbSuppliesDTOList = page.getContent().stream()
                .filter(item -> item.getTbCustomerId() == currentUser.getCustomerId() || item.getTbCustomerId() == null)
                .collect(Collectors.toList());
            page = pageableUtil.changeTBSuppliesDTOToPageFromList(tbSuppliesDTOList, pageable);
        }
        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/tb-supplies");
        return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
    }

    /**
     * GET  /tb-supplies : get all the tBSupplies.
     *
     * @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 tBSupplies in body
     */
    @GetMapping("/tb-supplies-dropdown-list")
    @Timed
    public ResponseEntity<List<TBSuppliesDTO>> getAllTBSuppliesDropdownList(@RequestParam(value = "q", required = false) String q,
                                                                @RequestParam(value = "suppliesTypeId", required = false) Long suppliesTypeId,
                                                                TBSuppliesCriteria criteria, Pageable pageable) {
        log.debug("REST request to get TBSupplies by criteria: {}", criteria);
        List<TBSuppliesDTO> tbSuppliesDTOList = tBSuppliesQueryService.getListTBSuppliesToCustomer(criteria, pageable, q, suppliesTypeId).getContent();
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        if (currentUser.getCustomerId() != null) {
            tbSuppliesDTOList = tbSuppliesDTOList.stream()
                .filter(item -> item.getTbCustomerId() == currentUser.getCustomerId() || item.getTbCustomerId() == null)
                .collect(Collectors.toList());
        }
        return new ResponseEntity<>(tbSuppliesDTOList, null, HttpStatus.OK);
    }

    /**
     * GET  /tb-supplies/seedling : get all the seedlings.
     *
     * @param criteria
     * @param pageable
     * @return
     */
    @GetMapping("/tb-supplies/seedling")
    @Timed
    public ResponseEntity<List<TBSuppliesDTO>> getAllSeedlings(TBSuppliesCriteria criteria, Pageable pageable) {
        log.debug("REST request to get seed by criteria: {}", criteria);
        TBSuppliesTypeDTO tbSuppliesTypeDTO = getTbSuppliesTypeDTO(GIONG.name());
        return getAllTBSupplies("", tbSuppliesTypeDTO.getId(), criteria, pageable);
    }

    /**
     * GET  /tb-supplies/seedling : get all the seedlings.
     *
     * @param criteria
     * @param pageable
     * @return
     */
    @GetMapping("/tb-supplies/seedling-dropdown-list")
    @Timed
    public ResponseEntity<List<TBSuppliesDTO>> getAllSeedlingsDropdownList(TBSuppliesCriteria criteria, Pageable pageable) {
        log.debug("REST request to get seed by criteria: {}", criteria);
        TBSuppliesTypeDTO tbSuppliesTypeDTO = getTbSuppliesTypeDTO(GIONG.name());
        return getAllTBSuppliesDropdownList("", tbSuppliesTypeDTO.getId(), criteria, pageable);
    }

    /**
     * GET  /tb-supplies : get all the tBSupplies.
     *
     * @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 tBSupplies in body
     */
    @GetMapping("/tb-supplies-by-type/{suppliesType}")
    @Timed
    public ResponseEntity<List<TBSuppliesDTO>> getTBSuppliesByType(@PathVariable String suppliesType, TBSuppliesCriteria criteria, Pageable pageable) {
        log.debug("REST request to get TBSupplies by criteria: {}", criteria);

        TBSuppliesTypeDTO tbSuppliesTypeDTO = getTbSuppliesTypeDTO(suppliesType.toUpperCase());

        LongFilter suppliesTypeFilter = new LongFilter();
        suppliesTypeFilter.setEquals(tbSuppliesTypeDTO.getId());
        criteria.setTbSuppliesTypeId(suppliesTypeFilter);

        Page<TBSuppliesDTO> page = tBSuppliesQueryService.findByCriteria(criteria, pageable);
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        if (currentUser.getCustomerId() != null) {
            List<TBSuppliesDTO> tbSuppliesDTOList = page.getContent().stream()
                .filter(item -> item.getTbCustomerId() == currentUser.getCustomerId() || item.getTbCustomerId() == null)
                .collect(Collectors.toList());
            page = pageableUtil.changeTBSuppliesDTOToPageFromList(tbSuppliesDTOList, pageable);
        }
        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/tb-supplies");
        return ResponseEntity.ok().headers(headers).body(page.getContent());
    }

    /**
     * GET  /tb-supplies/count : count all the tBSupplies.
     *
     * @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/count")
    @Timed
    public ResponseEntity<Long> countTBSupplies(TBSuppliesCriteria criteria) {
        log.debug("REST request to count TBSupplies by criteria: {}", criteria);
        return ResponseEntity.ok().body(tBSuppliesQueryService.countByCriteria(criteria));
    }

    /**
     * GET  /tb-supplies/:id : get the "id" tBSupplies.
     *
     * @param id the id of the tBSuppliesDTO to retrieve
     * @return the ResponseEntity with status 200 (OK) and with body the tBSuppliesDTO, or with status 404 (Not Found)
     */
    @GetMapping("/tb-supplies/{id}")
    @Timed
    public ResponseEntity<TBSuppliesDTO> getTBSupplies(@PathVariable Long id) {
        log.debug("REST request to get TBSupplies : {}", id);
        Optional<TBSuppliesDTO> tBSuppliesDTO = tBSuppliesService.findOne(id);
        UserDTO currentUser = userService.getCurrentUserDTO().get();

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

    /**
     * DELETE  /tb-supplies/:id : delete the "id" tBSupplies.
     *
     * @param id the id of the tBSuppliesDTO to delete
     * @return the ResponseEntity with status 200 (OK)
     */
    @DeleteMapping("/tb-supplies/{id}")
    @Timed
    public ResponseEntity<Void> deleteTBSupplies(@PathVariable Long id) {
        log.debug("REST request to delete TBSupplies : {}", id);
        TBSuppliesDTO old_tbSuppliesDTO = tBSuppliesService.findOne(id).get();
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        old_tbSuppliesDTO.setDeletedDate(Instant.now());
        old_tbSuppliesDTO.setDeletedById(currentUser.getId());
        if (currentUser.getCustomerId() != null
            && old_tbSuppliesDTO.getTbCustomerId() != null
            && currentUser.getCustomerId() != old_tbSuppliesDTO.getTbCustomerId()){
            throw new BadRequestAlertException("1013", ENTITY_NAME, "1013");
        }
        tBSuppliesService.save(old_tbSuppliesDTO);
        return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, id.toString())).build();
    }

    /**
     * SEARCH  /_search/tb-supplies?query=:query : search for the tBSupplies corresponding
     * to the query.
     *
     * @param query    the query of the tBSupplies search
     * @param pageable the pagination information
     * @return the result of the search
     */
    @GetMapping("/_search/tb-supplies")
    @Timed
    public ResponseEntity<List<TBSuppliesDTO>> searchTBSupplies(@RequestParam String query, Pageable pageable) {
        log.debug("REST request to search for a page of TBSupplies for query {}", query);
        Page<TBSuppliesDTO> page = tBSuppliesService.search(query, pageable);
        //@CUONGLT - Filter scope customer's data
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        if (currentUser.getCustomerId() != null) {
            List<TBSuppliesDTO> tbSuppliesDTOList = page.getContent().stream()
                .filter(item -> item.getTbCustomerId() == null
                    || item.getTbCustomerId().equals(currentUser.getCustomerId())
                    && !item.getTbSuppliesTypeName().equals(GIONG.name()))
                .collect(Collectors.toList());
            page = pageableUtil.changeTBSuppliesDTOToPageFromList(tbSuppliesDTOList, pageable);
        }
        HttpHeaders headers = PaginationUtil.generateSearchPaginationHttpHeaders(query, page, "/api/_search/tb-supplies");
        return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
    }

    @GetMapping("/_search/tb-supplies/seed")
    @Timed
    public ResponseEntity<List<TBSuppliesDTO>> searchSeeds(@RequestParam String query, TBSuppliesCriteria criteria, Pageable pageable) {
        log.debug("REST request to search for a page of TBSupplies for query {}", query);
        TBSuppliesTypeDTO tbSuppliesTypeDTO = getTbSuppliesTypeDTO(GIONG.name());
        return getAllTBSupplies(query, tbSuppliesTypeDTO.getId(), criteria, pageable);
    }

    private TBSuppliesTypeDTO getTbSuppliesTypeDTO(String name) {
        StringFilter suppliesTypeName = new StringFilter();
        suppliesTypeName.setEquals(name);
        TBSuppliesTypeCriteria tbSuppliesTypeCriteria = new TBSuppliesTypeCriteria();
        tbSuppliesTypeCriteria.setName(suppliesTypeName);
        return tBSuppliesTypeQueryService.findByCriteria(tbSuppliesTypeCriteria).get(0);
    }

    @GetMapping("/tb-supplies/seed-units")
    @Timed
    public ResponseEntity<List<UnitDTO>> getAllWaterTypes(Pageable pageable) {
        log.debug("REST request to get Unit");
        Page<UnitDTO> page = tBSuppliesQueryService.getUnits(pageable);
        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/tb-supplies/seed-units");
        return ResponseEntity.ok().headers(headers).body(page.getContent());
    }
}
