package vn.azteam.tpf.web.rest;

import com.codahale.metrics.annotation.Timed;
import vn.azteam.tpf.service.TBGuidelinePeriodService;
import vn.azteam.tpf.service.TBGuidelineService;
import vn.azteam.tpf.service.UserService;
import vn.azteam.tpf.web.rest.errors.BadRequestAlertException;
import vn.azteam.tpf.web.rest.errors.ErrorCodes;
import vn.azteam.tpf.web.rest.util.HeaderUtil;
import vn.azteam.tpf.web.rest.util.PaginationUtil;
import vn.azteam.tpf.service.dto.TBGuidelinePeriodDTO;
import vn.azteam.tpf.service.dto.UserDTO;
import vn.azteam.tpf.service.dto.TBGuidelineDTO;
import vn.azteam.tpf.service.dto.TBGuidelinePeriodCriteria;
import vn.azteam.tpf.service.TBGuidelinePeriodQueryService;
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.StreamSupport;

import javax.validation.Valid;

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

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

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

    private static final String ENTITY_NAME = "tBGuidelinePeriod";

    private final TBGuidelinePeriodService tBGuidelinePeriodService;

    private final TBGuidelinePeriodQueryService tBGuidelinePeriodQueryService;

    private final TBGuidelineService tBGuidelineService;

    private final UserService userService;

    public TBGuidelinePeriodResource(TBGuidelinePeriodService tBGuidelinePeriodService,
                                     TBGuidelinePeriodQueryService tBGuidelinePeriodQueryService,
                                     TBGuidelineService tBGuidelineService,
                                     UserService userService) {
        this.tBGuidelinePeriodService = tBGuidelinePeriodService;
        this.tBGuidelinePeriodQueryService = tBGuidelinePeriodQueryService;
        this.tBGuidelineService = tBGuidelineService;
        this.userService = userService;
    }

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

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

    /**
     * GET  /tb-guideline-periods : get all the tBGuidelinePeriods.
     *
     * @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 tBGuidelinePeriods in body
     */
    @GetMapping("/tb-guideline-periods")
    @Timed
    public ResponseEntity<List<TBGuidelinePeriodDTO>> getAllTBGuidelinePeriods(TBGuidelinePeriodCriteria criteria, Pageable pageable) {
        log.debug("REST request to get TBGuidelinePeriods by criteria: {}", criteria);
        Page<TBGuidelinePeriodDTO> page = tBGuidelinePeriodQueryService.findByCriteria(criteria, pageable);
        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/tb-guideline-periods");
        return ResponseEntity.ok().headers(headers).body(page.getContent());
    }

    /**
    * GET  /tb-guideline-periods/count : count all the tBGuidelinePeriods.
    *
    * @param criteria the criterias which the requested entities should match
    * @return the ResponseEntity with status 200 (OK) and the count in body
    */
    @GetMapping("/tb-guideline-periods/count")
    @Timed
    public ResponseEntity<Long> countTBGuidelinePeriods(TBGuidelinePeriodCriteria criteria) {
        log.debug("REST request to count TBGuidelinePeriods by criteria: {}", criteria);
        return ResponseEntity.ok().body(tBGuidelinePeriodQueryService.countByCriteria(criteria));
    }

    /**
     * GET  /tb-guideline-periods/:id : get the "id" tBGuidelinePeriod.
     *
     * @param id the id of the tBGuidelinePeriodDTO to retrieve
     * @return the ResponseEntity with status 200 (OK) and with body the tBGuidelinePeriodDTO, or with status 404 (Not Found)
     */
    @GetMapping("/tb-guideline-periods/{id}")
    @Timed
    public ResponseEntity<TBGuidelinePeriodDTO> getTBGuidelinePeriod(@PathVariable Long id) {
        log.debug("REST request to get TBGuidelinePeriod : {}", id);
        Optional<TBGuidelinePeriodDTO> tBGuidelinePeriodDTO = tBGuidelinePeriodService.findOne(id);
        return ResponseUtil.wrapOrNotFound(tBGuidelinePeriodDTO);
    }

    /**
     * DELETE  /tb-guideline-periods/:id : delete the "id" tBGuidelinePeriod.
     *
     * @param id the id of the tBGuidelinePeriodDTO to delete
     * @return the ResponseEntity with status 200 (OK)
     */
    @DeleteMapping("/tb-guideline-periods/{id}")
    @Timed
    public ResponseEntity<Void> deleteTBGuidelinePeriod(@PathVariable Long id) {
        log.debug("REST request to delete TBGuidelinePeriod : {}", id);
        TBGuidelinePeriodDTO tbGuidelinePeriodDTO = tBGuidelinePeriodService.findOne(id)
                .orElseThrow(() -> new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull")
        );
        tBGuidelinePeriodService.delete(tbGuidelinePeriodDTO.getId());
        return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, id.toString())).build();
    }

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

    /**
     * Validate Request Method DTOs: Create, Update
     * @param tbGuidelinePeriodDTO
     */
    private void validate(@RequestBody TBGuidelinePeriodDTO tbGuidelinePeriodDTO) {
        if (tbGuidelinePeriodDTO.getAgeDayStart() == null) {
            throw new BadRequestAlertException("1044", ENTITY_NAME, "1044");
        }
        if (tbGuidelinePeriodDTO.getAgeDayEnd() != null &&
            tbGuidelinePeriodDTO.getAgeDayEnd() < tbGuidelinePeriodDTO.getAgeDayStart()) {
            throw new BadRequestAlertException("1145", ENTITY_NAME, "1145");
        }
        if (tbGuidelinePeriodDTO.getTbGuidelineId() != null) {
            Optional<TBGuidelineDTO> tBGuidelineDTO = tBGuidelineService.findOne(tbGuidelinePeriodDTO.getTbGuidelineId());
            if (!tBGuidelineDTO.isPresent()) {
                throw new BadRequestAlertException(ErrorCodes.ACCESS_GUIDELINE_DENIED, ENTITY_NAME, ErrorCodes.ACCESS_GUIDELINE_DENIED);
            }
            UserDTO currentUser = userService.getCurrentUserDTO().get();
            if (currentUser.getCustomerId() != null
                && tBGuidelineDTO.get().getTbCustomerId() != null
                && tBGuidelineDTO.get().getTbCustomerId() != currentUser.getCustomerId()) {
                throw new BadRequestAlertException(ErrorCodes.ACCESS_GUIDELINE_DENIED, ENTITY_NAME, ErrorCodes.ACCESS_GUIDELINE_DENIED);
            }
        }
    }
}
