package it.micegroup.gestioneferie.configurazionepf.controller;

import lombok.RequiredArgsConstructor;
import it.micegroup.gestioneferie.configurazionepf.entity.DpercAutPianFerieH;
import it.micegroup.gestioneferie.configurazionepf.assembler.DpercAutPianFerieHModelAssembler;
import it.micegroup.gestioneferie.configurazionepf.criteria.DpercAutPianFerieHCriteria;
import it.micegroup.gestioneferie.configurazionepf.service.DpercAutPianFerieHService;

import it.micegroup.gestioneferie.configurazionepf.entity.DpercAutPianFeriePk;
import it.micegroup.gestioneferie.configurazionepf.entity.DconfigPaPianiFerie;

import it.micegroup.voila2runtime.exception.*;
import it.micegroup.gestioneferie.libs.controller.BaseController;
import it.micegroup.gestioneferie.configurazionepf.dto.DpercAutPianFerieHDto;
import it.micegroup.gestioneferie.configurazionepf.dto.DpercAutPianFerieHWriteDto;
import it.micegroup.gestioneferie.libs.response.BaseResponse;
import it.micegroup.gestioneferie.libs.request.BaseRequest;
import javax.annotation.PostConstruct;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PagedResourcesAssembler;
import org.springframework.hateoas.PagedModel;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import javax.validation.Valid;
import java.net.URI;
import java.util.Locale;
import java.util.Optional;

import java.util.Collection;
import org.modelmapper.PropertyMap;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@RestController
@RequestMapping(value = "/dperc-aut-pian-ferie-h", produces = MediaType.APPLICATION_JSON_VALUE)
public class DpercAutPianFerieHController extends BaseController<BaseResponse<DpercAutPianFerieHDto>> {

	/// ENTITY SERVICE
	private final DpercAutPianFerieHService dpercAutPianFerieHService;
	private final DpercAutPianFerieHModelAssembler dpercAutPianFerieHModelAssembler;
	private final PagedResourcesAssembler<DpercAutPianFerieH> pagedResourcesAssembler;
	private final ModelMapper modelMapper;
	// CHILD SERVICES

	// CONSTRUCTOR
	@PostConstruct
	public void postConstruct() {
	}

	@SuppressWarnings("unused")
	private static final Logger LOGGER = LogManager.getLogger(DpercAutPianFerieHController.class);

	// API
	@GetMapping
	@PreAuthorize("hasRole(@permissionHolder.DPERC_AUT_PIAN_FERIE_H_FIND_PAGINATED.toString())")
	public ResponseEntity<BaseResponse<PagedModel<DpercAutPianFerieHDto>>> findPaginated(
			DpercAutPianFerieHCriteria criteria, Pageable pageable) {
		Page<DpercAutPianFerieH> page = dpercAutPianFerieHService.findByCriteria(criteria, pageable);
		return toResponseEntityPaged(page, null);
	}

	/**
	 * {@code GET  /dperc-aut-pian-ferie-h/:objectKey} : get the
	 * dperc-aut-pian-ferie-h with given objectKey.
	 *
	 * @param objectKey the objectKey of the dperc-aut-pian-ferie-h to retrieve.
	 * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body
	 *         the dperc-aut-pian-ferie-h, or with status {@code 404 (Not Found)}.
	 */
	@GetMapping("/{objectKey:.+}")
	@PreAuthorize("hasRole(@permissionHolder.DPERC_AUT_PIAN_FERIE_H_FIND_BY_ID.toString())")
	public ResponseEntity<BaseResponse<DpercAutPianFerieHDto>> getByObjectKey(@PathVariable String objectKey) {
		return toResponseEntity(dpercAutPianFerieHService.findByObjectKey(objectKey), null, HttpStatus.OK);
	}

	/**
	 * {@code PUT  /dperc-aut-pian-ferie-h} : Updates an existing
	 * DpercAutPianFerieH.
	 *
	 * @param DpercAutPianFerieH the DpercAutPianFerieH to update.
	 * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body
	 *         the updated DpercAutPianFerieH, or with status
	 *         {@code 400 (Bad Request)} if the DpercAutPianFerieH is not valid, or
	 *         with status {@code 500 (Internal Server Error)} if the
	 *         DpercAutPianFerieH couldn't be updated.
	 */
	@PutMapping
	@PreAuthorize("hasRole(@permissionHolder.DPERC_AUT_PIAN_FERIE_H_UPDATE.toString())")
	public ResponseEntity<?> update(@Valid @RequestBody BaseRequest<DpercAutPianFerieHWriteDto> request) {
		return toResponseEntity(
				Optional.of(dpercAutPianFerieHService
						.bulkUpdate(modelMapper.map(request.getData(), DpercAutPianFerieH.class))),
				null, HttpStatus.OK);
	}

	/**
	 * {@code POST  /dperc-aut-pian-ferie-h} : Create a new DpercAutPianFerieH.
	 *
	 * @param DpercAutPianFerieH the DpercAutPianFerieH to create.
	 * @return the {@link ResponseEntity} with status {@code 201 (Created)} and with
	 *         body the new DpercAutPianFerieH, or with status
	 *         {@code 400 (Bad Request)} if the DpercAutPianFerieH has already an
	 *         ID.
	 * @throws URISyntaxException if the Location URI syntax is incorrect.
	 */
	@PostMapping
	@PreAuthorize("hasRole(@permissionHolder.DPERC_AUT_PIAN_FERIE_H_CREATE.toString())")
	public ResponseEntity<?> save(@Valid @RequestBody BaseRequest<DpercAutPianFerieHWriteDto> request) {
		ResponseEntity<?> response = null;
		DpercAutPianFerieH dpercAutPianFerieHToInsert = childMap(request.getData());
		try {
			DpercAutPianFerieH newDpercAutPianFerieH = dpercAutPianFerieHService
					.insert(modelMapper.map(dpercAutPianFerieHToInsert, DpercAutPianFerieH.class));
			URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
					.buildAndExpand(newDpercAutPianFerieH.getSequIdPercAutPianFerieH()).toUri();
			HttpHeaders headers = new HttpHeaders();
			headers.setLocation(location);
			response = toResponseEntity(Optional.of(newDpercAutPianFerieH), headers, HttpStatus.CREATED);
		} catch (Exception exception) {
			LOGGER.error("Exception:", exception);
		}
		return response;
	}

	private DpercAutPianFerieH childMap(DpercAutPianFerieHWriteDto data) {
		DpercAutPianFerieH dpercAutPianFerieHToInsert = modelMapper.map(data, DpercAutPianFerieH.class);
		return dpercAutPianFerieHToInsert;
	}

	/**
	 * {@code DELETE  /dperc-aut-pian-ferie-h/:objectKey} : delete the
	 * dperc-aut-pian-ferie-h with given objectKey.
	 *
	 * @param objectKey the objectKey of the DpercAutPianFerieH to delete.
	 * @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}.
	 */
	@DeleteMapping("/{objectKey:.+}")
	@PreAuthorize("hasRole(@permissionHolder.DPERC_AUT_PIAN_FERIE_H_DELETE.toString())")
	public ResponseEntity<?> delete(@PathVariable String objectKey) {
		dpercAutPianFerieHService
				.deleteById(dpercAutPianFerieHService.findByObjectKey(objectKey).get().getSequIdPercAutPianFerieH());
		return new ResponseEntity<>(new BaseResponse<>(objectKey), HttpStatus.OK);
	}

	/**
	 * GET /the-dperc-aut-pian-ferie-pk_id: Search all DpercAutPianFerieH for the
	 * given DpercAutPianFeriePk (parent)
	 * 
	 * @param OK       of DpercAutPianFeriePk
	 * @param pageable
	 * @return Page of DpercAutPianFerieH for the given DpercAutPianFeriePk (parent)
	 */
	@GetMapping("/findByTheDpercAutPianFeriePk/{dpercAutPianFeriePkObjectKey:.+}")
	@PreAuthorize("hasRole(@permissionHolder.DPERC_AUT_PIAN_FERIE_H_FIND_BY_DPERC_AUT_PIAN_FERIE_PK.toString())")
	public ResponseEntity<BaseResponse<PagedModel<DpercAutPianFerieHDto>>> findByDpercAutPianFeriePk(
			@PathVariable String dpercAutPianFeriePkObjectKey, Pageable pageable) {
		DpercAutPianFeriePk key = new DpercAutPianFeriePk(dpercAutPianFeriePkObjectKey);
		return toResponseEntityPaged(dpercAutPianFerieHService.findByTheDpercAutPianFeriePk(key, pageable), null);
	}

	/**
	 * GET /the-dconfig-pa-piani-ferie_id: Search all DpercAutPianFerieH for the
	 * given DconfigPaPianiFerie (parent)
	 * 
	 * @param OK       of DconfigPaPianiFerie
	 * @param pageable
	 * @return Page of DpercAutPianFerieH for the given DconfigPaPianiFerie (parent)
	 */
	@GetMapping("/findByTheDconfigPaPianiFerie/{dconfigPaPianiFerieObjectKey:.+}")
	@PreAuthorize("hasRole(@permissionHolder.DPERC_AUT_PIAN_FERIE_H_FIND_BY_DCONFIG_PA_PIANI_FERIE.toString())")
	public ResponseEntity<BaseResponse<PagedModel<DpercAutPianFerieHDto>>> findByDconfigPaPianiFerie(
			@PathVariable String dconfigPaPianiFerieObjectKey, Pageable pageable) {
		DconfigPaPianiFerie key = new DconfigPaPianiFerie(dconfigPaPianiFerieObjectKey);
		return toResponseEntityPaged(dpercAutPianFerieHService.findByTheDconfigPaPianiFerie(key, pageable), null);
	}

	private ResponseEntity<BaseResponse<DpercAutPianFerieHDto>> toResponseEntity(
			Optional<DpercAutPianFerieH> maybeResponse, HttpHeaders header, HttpStatus status) {
		return maybeResponse
				.map(response -> new ResponseEntity<>(
						new BaseResponse<>(dpercAutPianFerieHModelAssembler.toModel(response)), header, status))
				.orElseThrow(() -> new NotFoundException(DpercAutPianFerieH.class, new Locale("it")));
	}

	private ResponseEntity<BaseResponse<PagedModel<DpercAutPianFerieHDto>>> toResponseEntityPaged(
			Page<DpercAutPianFerieH> list, HttpHeaders header) {
		BaseResponse<PagedModel<DpercAutPianFerieHDto>> collModel = new BaseResponse<>(
				pagedResourcesAssembler.toModel(list, dpercAutPianFerieHModelAssembler));
		return ResponseEntity.ok().headers(header).body(collModel);
	}

	@SuppressWarnings("unused")
	private DpercAutPianFerieH dtoToEntity(DpercAutPianFerieHDto dto) {
		return new ModelMapper().map(dto, DpercAutPianFerieH.class);
	}
}
