package vn.azteam.tpf.web.rest;

import com.codahale.metrics.annotation.Timed;
import org.casbin.jcasbin.main.Enforcer;
import org.springframework.data.domain.PageImpl;
import vn.azteam.tpf.service.TBEquipmentOfCustomerService;
import vn.azteam.tpf.service.TBEquipmentService;
import vn.azteam.tpf.service.UserService;
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.util.HeaderUtil;
import vn.azteam.tpf.web.rest.util.PaginationUtil;
import vn.azteam.tpf.service.TBEquipmentOfCustomerQueryService;
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 TBEquipmentOfCustomer.
 */
@RestController
@RequestMapping("/api")
public class TBEquipmentOfCustomerResource {

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

    private static final String ENTITY_NAME = "tBEquipmentOfCustomer";

    private final TBEquipmentOfCustomerService tBEquipmentOfCustomerService;

    private final UserService userService;

    private final TBEquipmentService tBEquipmentService;

    private final TBEquipmentOfCustomerQueryService tBEquipmentOfCustomerQueryService;

    private final Enforcer enforcer;

    private final UserRoleUtil userRoleUtil;

    private final PageableUtil pageableUtil;

    public TBEquipmentOfCustomerResource(TBEquipmentOfCustomerService tBEquipmentOfCustomerService,
                                         UserService userService,
                                         TBEquipmentService tBEquipmentService,
                                         Enforcer enforcer,
                                         TBEquipmentOfCustomerQueryService tBEquipmentOfCustomerQueryService,
                                         UserRoleUtil userRoleUtil, PageableUtil pageableUtil) {
        this.tBEquipmentOfCustomerService = tBEquipmentOfCustomerService;
        this.userService = userService;
        this.tBEquipmentService = tBEquipmentService;
        this.tBEquipmentOfCustomerQueryService = tBEquipmentOfCustomerQueryService;
        this.enforcer = enforcer;
        this.userRoleUtil = userRoleUtil;
        this.pageableUtil = pageableUtil;
    }

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

    /**
     * PUT  /tb-equipment-of-customers : Updates an existing tBEquipmentOfCustomer.
     *
     * @param tBEquipmentOfCustomerDTO the tBEquipmentOfCustomerDTO to update
     * @return the ResponseEntity with status 200 (OK) and with body the updated tBEquipmentOfCustomerDTO,
     * or with status 400 (Bad Request) if the tBEquipmentOfCustomerDTO is not valid,
     * or with status 500 (Internal Server Error) if the tBEquipmentOfCustomerDTO couldn't be updated
     * @throws URISyntaxException if the Location URI syntax is incorrect
     */
    @PutMapping("/tb-equipment-of-customers")
    @Timed
    public ResponseEntity<TBEquipmentOfCustomerDTO> updateTBEquipmentOfCustomer(@RequestBody TBEquipmentOfCustomerDTO tBEquipmentOfCustomerDTO) throws URISyntaxException {
        log.debug("REST request to update TBEquipmentOfCustomer : {}", tBEquipmentOfCustomerDTO);
        if (tBEquipmentOfCustomerDTO.getId() == null) {
            throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull");
        }
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        Optional<TBEquipmentOfCustomerDTO> dbEquipmentOfCustomerDTO = tBEquipmentOfCustomerService.findOne(tBEquipmentOfCustomerDTO.getId());
        if(currentUser.getCustomerId() != null
            && !userRoleUtil.currentUserHasPermissionByEntityId(dbEquipmentOfCustomerDTO.get().getTbEntityId())){
            throw new BadRequestAlertException("1058", ENTITY_NAME, "1058");
        }
        TBEquipmentOfCustomerDTO result = tBEquipmentOfCustomerService.save(tBEquipmentOfCustomerDTO);

        return ResponseEntity.ok()
            .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, tBEquipmentOfCustomerDTO.getId().toString()))
            .body(result);
    }

    /**
     * GET  /tb-equipment-of-customers : get all the tBEquipmentOfCustomers.
     *
     * @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 tBEquipmentOfCustomers in body
     */
    @GetMapping("/tb-equipment-of-customers")
    @Timed
    public ResponseEntity<List<TBEquipmentOfCustomerDTO>> getAllTBEquipmentOfCustomers(TBEquipmentOfCustomerCriteria criteria, Pageable pageable) {
        log.debug("REST request to get TBEquipmentOfCustomers by criteria: {}", criteria);
        Page<TBEquipmentOfCustomerDTO> page = tBEquipmentOfCustomerQueryService.findByCriteria(criteria, pageable);
        //authorize by role
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        if (currentUser.getCustomerId() != null) {
            List<TBEquipmentOfCustomerDTO> lstEquipmentOfCustomerDTOS = page.getContent().stream().filter(item -> item.getTbEntityId() != null && userRoleUtil.currentUserHasPermissionByEntityId(item.getTbEntityId())
                && item.getTbCustomerId() == currentUser.getCustomerId())
                .collect(Collectors.toList());

            page = pageableUtil.changeTBEquipmentOfCustomerDTOToPageFromList(lstEquipmentOfCustomerDTOS, pageable);
        }
        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/tb-equipment-of-customers");
        return ResponseEntity.ok().headers(headers).body(page.getContent());
    }

    /**
    * GET  /tb-equipment-of-customers/count : count all the tBEquipmentOfCustomers.
    *
    * @param criteria the criterias which the requested entities should match
    * @return the ResponseEntity with status 200 (OK) and the count in body
    */
    @GetMapping("/tb-equipment-of-customers/count")
    @Timed
    public ResponseEntity<Long> countTBEquipmentOfCustomers(TBEquipmentOfCustomerCriteria criteria) {
        log.debug("REST request to count TBEquipmentOfCustomers by criteria: {}", criteria);
        return ResponseEntity.ok().body(tBEquipmentOfCustomerQueryService.countByCriteria(criteria));
    }

    /**
     * GET  /tb-equipment-of-customers/:id : get the "id" tBEquipmentOfCustomer.
     *
     * @param id the id of the tBEquipmentOfCustomerDTO to retrieve
     * @return the ResponseEntity with status 200 (OK) and with body the tBEquipmentOfCustomerDTO, or with status 404 (Not Found)
     */
    @GetMapping("/tb-equipment-of-customers/{id}")
    @Timed
    public ResponseEntity<TBEquipmentOfCustomerDTO> getTBEquipmentOfCustomer(@PathVariable Long id) {
        log.debug("REST request to get TBEquipmentOfCustomer : {}", id);
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        Optional<TBEquipmentOfCustomerDTO> tBEquipmentOfCustomerDTO = tBEquipmentOfCustomerService.findOne(id);
        if(currentUser.getCustomerId() != null
            && !userRoleUtil.currentUserHasPermissionByEntityId(tBEquipmentOfCustomerDTO.get().getTbEntityId())){
            throw new BadRequestAlertException("1058", ENTITY_NAME, "1058");
        }
        return ResponseUtil.wrapOrNotFound(tBEquipmentOfCustomerDTO);
    }

    /**
     * DELETE  /tb-equipment-of-customers/:id : delete the "id" tBEquipmentOfCustomer.
     *
     * @param id the id of the tBEquipmentOfCustomerDTO to delete
     * @return the ResponseEntity with status 200 (OK)
     */
    @DeleteMapping("/tb-equipment-of-customers/{id}")
    @Timed
    public ResponseEntity<Void> deleteTBEquipmentOfCustomer(@PathVariable Long id) {
        log.debug("REST request to delete TBEquipmentOfCustomer : {}", id);
        Optional<TBEquipmentDTO> tBEquipmentDTO = tBEquipmentService.findOne(id);
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        if (currentUser.getCustomerId() != null
            && currentUser.getCustomerId() != tBEquipmentDTO.get().getTbCustomerId()){
            throw new BadRequestAlertException("1019", ENTITY_NAME, "1019");
        }
        Optional<TBEquipmentOfCustomerDTO> equipmentOfCustomerDTO = tBEquipmentOfCustomerService.findOne(id);
        if(currentUser.getCustomerId() != null
            && !userRoleUtil.currentUserHasPermissionByEntityId(equipmentOfCustomerDTO.get().getTbEntityId())){
            throw new BadRequestAlertException("1058", ENTITY_NAME, "1058");
        }
        Boolean delete = tBEquipmentOfCustomerQueryService.deleteEquipmentOfCustomer(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-equipment-of-customers?query=:query : search for the tBEquipmentOfCustomer corresponding
     * to the query.
     *
     * @param query the query of the tBEquipmentOfCustomer search
     * @param pageable the pagination information
     * @return the result of the search
     */
    @GetMapping("/_search/tb-equipment-of-customers")
    @Timed
    public ResponseEntity<List<TBEquipmentOfCustomerDTO>> searchTBEquipmentOfCustomers(@RequestParam String query, Pageable pageable) {
        log.debug("REST request to search for a page of TBEquipmentOfCustomers for query {}", query);
        Page<TBEquipmentOfCustomerDTO> page = tBEquipmentOfCustomerService.search(query, pageable);
        HttpHeaders headers = PaginationUtil.generateSearchPaginationHttpHeaders(query, page, "/api/_search/tb-equipment-of-customers");
        return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
    }

    //api dành cho app
    @GetMapping("/listDeviceOfUserCustomers")
    @Timed
    public ResponseEntity<List<TBEquipmentOfCustomerDTO>> getAllDeviceOfUserCustomersControlsInEntity(@RequestParam(value = "query", required=false) String query) {

        List<TBEquipmentOfCustomerDTO> result = tBEquipmentOfCustomerQueryService.getAllDeviceOfUserCustomersControl(query);
        UserDTO currentUser = userService.getCurrentUserDTO().get();

        if (currentUser.getCustomerId() != null) {
            result = result.stream().filter(item -> userRoleUtil.currentUserHasPermissionByEntityId(item.getTbEntityId())
                && item.getTbCustomerId() == currentUser.getCustomerId())
                .collect(Collectors.toList());
        }

        return ResponseEntity.ok().body(result);
    }
    @GetMapping("/listDevicesInEntity/{entityId}")
    @Timed
    public ResponseEntity<List<TBEquipmentOfCustomerDTO>> getDevicesInEntity(@PathVariable String entityId) {
        Long entityIdL;
        entityIdL = Long.parseLong(entityId);
        List<TBEquipmentOfCustomerDTO> result = tBEquipmentOfCustomerQueryService.getAllDeviceInEntity(entityIdL);
        return ResponseEntity.ok().body(result);
    }
    @GetMapping("/listDeviceForActivity")
    @Timed
    public ResponseEntity<List<TBEquipmentOfCustomerDTO>> getListDeviceForActivity(@RequestParam(value = "q", required=false) String q) {
        List<TBEquipmentOfCustomerDTO> result = tBEquipmentOfCustomerQueryService.getListDeviceForActivity(q);
        //@CUONGLT - Filter scope customer's data
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        if (currentUser.getCustomerId() != null) {
            result = result.stream()
                .filter(item -> item.getTbCustomerId() == currentUser.getCustomerId() || item.getTbCustomerId() == null)
                .collect(Collectors.toList());
        }
        return ResponseEntity.ok().body(result);
    }

    /**
     * PUT  /equipment-of-customers : Updates an existing equipmentOfCustomer.
     *
     * @param id the id of equipmentOfCustomer to update
     * @return the ResponseEntity with status 200 (OK) and with body the updated equipmentOfCustomerDTO,
     * or with status 400 (Bad Request) if the equipmentOfCustomerDTO is not valid,
     * or with status 500 (Internal Server Error) if the equipmentOfCustomerDTO couldn't be updated
     * @throws URISyntaxException if the Location URI syntax is incorrect
     */
    @PutMapping("/equipment-of-customers-on-off/{id}/{isOn}")
    @Timed
    public ResponseEntity<ControlTBEquipmentOfCustomerDTO> equipmentOfCustomerOnOff(@PathVariable Long id, @PathVariable String isOn) throws Exception {
        log.debug("REST request to update EquipmentOfCustomer : {}", id);
        Optional<TBEquipmentOfCustomerDTO> equipmentOfCustomerDTO = tBEquipmentOfCustomerService.findOne(id);
        ControlTBEquipmentOfCustomerDTO error = new ControlTBEquipmentOfCustomerDTO();
        error.setStatusCode(403);
        error.setMessage("Your account can't to control this deviced!");
        error.setTbEquipmentOfCustomerDTO(null);
        ControlTBEquipmentOfCustomerDTO result = null != equipmentOfCustomerDTO ? tBEquipmentOfCustomerQueryService.equipmentOfCustomerOnOff(equipmentOfCustomerDTO.get().getId(), isOn) : error;
        if(null != result && result.getStatusCode() == 200) {
            return ResponseEntity.ok()
                .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, id.toString()))
                .body(result);
        }
        return ResponseEntity.badRequest()
            .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, id.toString()))
            .body(result);
    }
    /**
     * LIST FOR SCREEN TABLE  /devicesOfUserCustomers
     * @param q the query of the tBEquipmentOfCustomer search
     * @param equipmentId the query of the tBEquipmentOfCustomer search
     * @param pageable the pagination information
     * @return the result of the search
     */
    @GetMapping("/devicesOfUserCustomers")
    @Timed
    public ResponseEntity<List<TBEquipmentOfCustomerDTO>> getDevicesOfUserCustomers(@RequestParam(value = "q", required=false) String q,
                                                                                    @RequestParam(value = "equipmentTypeId", required=false) Long equipmentTypeId,
                                                                                    @RequestParam(value = "equipmentId", required=false) Long equipmentId,
                                                                                    TBEquipmentOfCustomerCriteria criteria, Pageable pageable) {
        Page<TBEquipmentOfCustomerDTO> page = tBEquipmentOfCustomerQueryService.getDevicesOfUserCustomers(criteria, pageable, q,equipmentTypeId, equipmentId);

        //authorize by role
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        if (currentUser.getCustomerId() != null) {
            List<TBEquipmentOfCustomerDTO> lstEquipmentOfCustomerDTOS = page.getContent().stream().filter(item -> item.getTbEntityId() != null && userRoleUtil.currentUserHasPermissionByEntityId(item.getTbEntityId())
                && item.getTbCustomerId() == currentUser.getCustomerId())
                .collect(Collectors.toList());

            page = pageableUtil.changeTBEquipmentOfCustomerDTOToPageFromList(lstEquipmentOfCustomerDTOS, pageable);
        }

        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/devicesOfUserCustomers");
        return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
    }

    @GetMapping("/locationDevices")
    @Timed
    public ResponseEntity<List<LocationDevicesDTO>> listLocationDevices() {
        //authorize by role
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        List<LocationDevicesDTO> result = tBEquipmentOfCustomerQueryService.listLocationDevices();
        if (currentUser.getCustomerId() != null) {
            result = result.stream().filter(item -> item.getCustomerId() != null
                && item.getCustomerId() == currentUser.getCustomerId())
                .collect(Collectors.toList());
        }
        return ResponseEntity.ok().body(result);

    }

    @PostMapping("/create-tb-equipment-of-customers")
    @Timed
    public ResponseEntity<TBEquipmentOfCustomerDTO> createNewTBEquipmentOfCustomer(@RequestBody DevicesDTO tbDevicesDTO) throws URISyntaxException {
        //@CUONGLT - Filter scope customer's data
        Optional<TBEquipmentDTO> tBEquipmentDTO = tBEquipmentService.findOne(tbDevicesDTO.getTbEquipmentId());
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        if (currentUser.getCustomerId() != null
            && currentUser.getCustomerId() != tBEquipmentDTO.get().getTbCustomerId()){
            throw new BadRequestAlertException("1019", ENTITY_NAME, "1019");
        }
        TBEquipmentOfCustomerDTO result = tBEquipmentOfCustomerQueryService.createTBEquipmentOfCustomer(tbDevicesDTO);
        return ResponseEntity.created(new URI("/api/tb-equipment-of-customers/" + result.getId()))
            .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
            .body(result);
    }

    @PutMapping("/update-tb-equipment-of-customers")
    @Timed
    public ResponseEntity<TBEquipmentOfCustomerDTO> updateNewTBEquipmentOfCustomer(@RequestBody DevicesDTO tbDevicesDTO) throws URISyntaxException {
        //@CUONGLT - Filter scope customer's data
        Optional<TBEquipmentDTO> tBEquipmentDTO = tBEquipmentService.findOne(tbDevicesDTO.getTbEquipmentId());
        UserDTO currentUser = userService.getCurrentUserDTO().get();
        TBEquipmentOfCustomerDTO result = tBEquipmentOfCustomerQueryService.updateTBEquipmentOfCustomer(tbDevicesDTO);
        if(currentUser.getCustomerId() != null && !userRoleUtil.currentUserHasPermissionByEntityId(result.getTbEntityId())){
            throw new BadRequestAlertException("1058", ENTITY_NAME, "1058");
        }
        return ResponseEntity.created(new URI("/api/tb-equipment-of-customers/" + result.getId()))
            .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
            .body(result);
    }
}
