package vn.azteam.tpf.web.rest;

import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.multipart.MultipartFile;
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.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.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

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

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

    private static final String ENTITY_NAME = "tBEquipment";

    private final TBEquipmentService tBEquipmentService;

    private final TBEquipmentQueryService tBEquipmentQueryService;

    private final ObjectMapper objectMapper;

    private final TBEquipmentTypeService tBEquipmentTypeService;

    private final TBEquipmentOfCustomerQueryService tBEquipmentOfCustomerQueryService;

    private final UserService userService;

    private final PageableUtil pageableUtil;

    public TBEquipmentResource(TBEquipmentService tBEquipmentService,
                               TBEquipmentQueryService tBEquipmentQueryService,
                               UserService userService,
                               ObjectMapper objectMapper, TBEquipmentTypeService tBEquipmentTypeService,
                               TBEquipmentOfCustomerQueryService tBEquipmentOfCustomerQueryService, PageableUtil pageableUtil) {
        this.tBEquipmentService = tBEquipmentService;
        this.tBEquipmentQueryService = tBEquipmentQueryService;
        this.userService = userService;
        this.objectMapper = objectMapper;
        this.tBEquipmentTypeService = tBEquipmentTypeService;
        this.tBEquipmentOfCustomerQueryService = tBEquipmentOfCustomerQueryService;
        this.pageableUtil = pageableUtil;
    }

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

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

    /**
     * GET  /tb-equipments : get all the tBEquipments.
     *
     * @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 tBEquipments in body
     */
    @GetMapping("/tb-equipments")
    @Timed
    public ResponseEntity<List<TBEquipmentDTO>> getAllTBEquipments(@RequestParam(value = "q", required = false) String q,
                                                                   @RequestParam(value = "equipmentTypeId", required = false) Long equipmentTypeId,
                                                                   TBEquipmentCriteria criteria, Pageable pageable) {
        log.debug("REST request to get TBEquipments by criteria: {}", criteria);
//        Long idEquipmentType = Long.parseLong(idEquipmentType);
        Page<TBEquipmentDTO> page = tBEquipmentQueryService.getAllTBEquipments(criteria, pageable, q, equipmentTypeId);
        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/tb-equipments");
        return ResponseEntity.ok().headers(headers).body(page.getContent());
    }

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

    /**
     * GET  /tb-equipments/:id : get the "id" tBEquipment.
     *
     * @param id the id of the tBEquipmentDTO to retrieve
     * @return the ResponseEntity with status 200 (OK) and with body the tBEquipmentDTO, or with status 404 (Not Found)
     */
    @GetMapping("/tb-equipments/{id}")
    @Timed
    public ResponseEntity<TBEquipmentDTO> getTBEquipment(@PathVariable Long id) {
        log.debug("REST request to get TBEquipment : {}", id);
        Optional<TBEquipmentDTO> tBEquipmentDTO = tBEquipmentService.findOne(id);

        //@CUONGLT - Filter scope customer's data
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        if (currentUser.getCustomerId() != null
            && currentUser.getCustomerId() != tBEquipmentDTO.get().getTbCustomerId()){
            throw new BadRequestAlertException("1019", ENTITY_NAME, "1019");
        }
        if (tBEquipmentDTO.isPresent()){
            TBEquipmentDTO tBEquipment = tBEquipmentDTO.get();
            tBEquipment.setGuide(tBEquipmentQueryService.parseSpecsTBEquipmentDTO(tBEquipment.getSpecs()));
            tBEquipment.setSpecs(null);
            tBEquipment.setInventory(tBEquipmentOfCustomerQueryService.totalDeviceInWarehouse(tBEquipment.getId()));
            return ResponseEntity.ok().body(tBEquipment);
        }
        return ResponseUtil.wrapOrNotFound(tBEquipmentDTO);
    }

    /**
     * DELETE  /tb-equipments/:id : delete the "id" tBEquipment.
     *
     * @param id the id of the tBEquipmentDTO to delete
     * @return the ResponseEntity with status 200 (OK)
     */
    @DeleteMapping("/tb-equipments/{id}")
    @Timed
    public ResponseEntity<Void> deleteTBEquipment(@PathVariable Long id) {
        log.debug("REST request to delete TBEquipment : {}", id);
//        tBEquipmentService.delete(id);
        //@CUONGLT - Filter scope customer's data
        Optional<TBEquipmentDTO> tBEquipmentDTO = tBEquipmentService.findOne(id);
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        if (currentUser.getCustomerId() != null
            && currentUser.getCustomerId() != tBEquipmentDTO.get().getTbCustomerId()){
            throw new BadRequestAlertException("1018", ENTITY_NAME, "1019");
        }
        Boolean delete = tBEquipmentQueryService.deleteTBEquipment(id);
        if (delete == Boolean.TRUE) {
            return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, "Delete OK")).build();
        } else {
            return ResponseEntity.badRequest().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, "Delete Error")).build();
        }
    }

    /**
     * SEARCH  /_search/tb-equipments?query=:query : search for the tBEquipment corresponding
     * to the query.
     *
     * @param query    the query of the tBEquipment search
     * @param pageable the pagination information
     * @return the result of the search
     */
    @GetMapping("/_search/tb-equipments")
    @Timed
    public ResponseEntity<List<TBEquipmentDTO>> searchTBEquipments(@RequestParam String query, Pageable pageable) {
        log.debug("REST request to search for a page of TBEquipments for query {}", query);
        Page<TBEquipmentDTO> page = tBEquipmentService.search(query, pageable);
        //@CUONGLT - Filter scope customer's data
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        if (currentUser.getCustomerId() != null) {
            List<TBEquipmentDTO> tbEquipmentDTOList = page.getContent().stream()
                .filter(item -> item.getTbCustomerId() == currentUser.getCustomerId())
                .collect(Collectors.toList());
            page = pageableUtil.changeTBEquipmentDTOToPageFromList(tbEquipmentDTOList, pageable);
        }
        HttpHeaders headers = PaginationUtil.generateSearchPaginationHttpHeaders(query, page, "/api/_search/tb-equipments");
        return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
    }

    @PostMapping("/updateTBEquipments")
    @Timed
    public ResponseEntity<TBEquipmentDTO> updateTBEquipments(@RequestParam("tbEquipment") String tbEquipment,
                                                             @RequestParam(value = "files") final MultipartFile[] files) {
        TBEquipmentDTO data = parseTBEquipmentDTOFromJsonString(tbEquipment);
        if (!tBEquipmentTypeService.findOne(data.getTbEquipmentTypeId()).isPresent()){
            throw new BadRequestAlertException("1043", ENTITY_NAME, "1043");
        }
        //@CUONGLT - Filter scope customer's data
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        if (currentUser.getCustomerId() != null) {
            data.setTbCustomerId(currentUser.getCustomerId());
        }
        TBEquipmentDTO result = tBEquipmentQueryService.updateTBEquipments(data, files);

        result.setGuide(tBEquipmentQueryService.parseSpecsTBEquipmentDTO(result.getSpecs()));
        result.setSpecs(null);
        return ResponseEntity.ok()
            .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, result.getId().toString()))
            .body(result);

    }

    @PostMapping("/createTBEquipments")
    @Timed
    public ResponseEntity<TBEquipmentDTO> createTBEquipments(@RequestParam("tbEquipment") String tbEquipment,
                                                             @RequestParam(value = "files") final MultipartFile[] files) {
        TBEquipmentDTO data = parseTBEquipmentDTOFromJsonString(tbEquipment);
        if (!tBEquipmentTypeService.findOne(data.getTbEquipmentTypeId()).isPresent()){
            throw new BadRequestAlertException("1043", ENTITY_NAME, "1043");
        }
        //@CUONGLT - Filter scope customer's data
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        if (currentUser.getCustomerId() != null) {
            data.setTbCustomerId(currentUser.getCustomerId());
        }
        TBEquipmentDTO result_change = tBEquipmentQueryService.createTBEquipments(data, files);
        TBEquipmentDTO result = tBEquipmentService.save(result_change);
        result.setGuide(tBEquipmentQueryService.parseSpecsTBEquipmentDTO(result_change.getSpecs()));
        result.setSpecs(null);
        return ResponseEntity.ok()
            .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, result.getId().toString()))
            .body(result);

    }

    private TBEquipmentDTO parseTBEquipmentDTOFromJsonString(String data_requet) {
        TBEquipmentDTO data;
        try {
            data = this.objectMapper.readValue(data_requet, TBEquipmentDTO.class);
        } catch (Exception e) {
            throw new BadRequestAlertException("1042", ENTITY_NAME, "1042");
        }
        return data;
    }

    @GetMapping("/tb-equipments-in-warehouse/{id}")
    @Timed
    public ResponseEntity<List<TBEntityDTO>> getAllTBEquipmentsInWarehouse(@PathVariable Long id) {
        List<TBEntityDTO> result = tBEquipmentQueryService.getAllTBEquipmentsInWarehouse(id);
        return ResponseEntity.ok().body(result);
    }
}
