package de.champonthis.buntspecht.controller.admin;

import java.time.Instant;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.querydsl.core.QueryResults;
import com.querydsl.core.Tuple;

import de.champonthis.buntspecht.businesslogic.TurnoverManager;
import de.champonthis.buntspecht.controller.BaseController;
import de.champonthis.buntspecht.controller.model.TurnoverFilterModel;
import de.champonthis.buntspecht.controller.model.TurnoverFilterModel.MinMax;
import de.champonthis.buntspecht.controller.support.EntityResponseStatusException;
import de.champonthis.buntspecht.controller.support.RequestBodyErrors;
import de.champonthis.buntspecht.controller.validation.TurnoverValidator;
import de.champonthis.buntspecht.model.Turnover;
import jakarta.transaction.Transactional;

@RestController
@RequestMapping("/turnovers/manage")
public class TurnoverManagementController extends BaseController {

	@Autowired
	private TurnoverManager turnoverManager;
	@Autowired
	private TurnoverValidator turnoverValidator;

	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@GetMapping
	@Transactional
	public QueryResults<Turnover> fetch(
			@RequestParam("username") Optional<String> usernameParameter,
			@RequestParam("limit") Optional<Long> limitParameter,
			@RequestParam("offset") Optional<Long> offsetParameter,
			@RequestParam("sort") Optional<String> sort,
			@RequestParam("descending") Optional<Boolean> descending,
			@RequestParam("from") Optional<Instant> from,
			@RequestParam("to") Optional<Instant> to,
			@RequestParam("customer") Optional<String> customer,
			@RequestParam("motif") Optional<String> motif) {

		TurnoverFilterModel filter = new TurnoverFilterModel();
		filter.setCreated(new MinMax<Instant>(from.orElse(null), to.orElse(null)));
		filter.setCustomer(customer.orElse(null));
		filter.setMotif(motif.orElse(null));

		return turnoverManager.fetch(usernameParameter.orElse(null), limitParameter.orElse(15L),
				offsetParameter.orElse(0L), sort.orElse("created"), descending.orElse(false), filter);
	}

	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@GetMapping("/overview")
	@Transactional
	public QueryResults<Tuple> overview(
			@RequestParam("username") Optional<String> usernameParameter,
			@RequestParam("limit") Optional<Long> limitParameter,
			@RequestParam("offset") Optional<Long> offsetParameter,
			@RequestParam("sort") Optional<String> sort,
			@RequestParam("descending") Optional<Boolean> descending,
			@RequestParam("from") Optional<Instant> from,
			@RequestParam("to") Optional<Instant> to,
			@RequestParam("customer") Optional<String> customer,
			@RequestParam("motif") Optional<String> motif) {

		TurnoverFilterModel filter = new TurnoverFilterModel();
		filter.setCreated(new MinMax<Instant>(from.orElse(null), to.orElse(null)));
		filter.setCustomer(customer.orElse(null));
		filter.setMotif(motif.orElse(null));
		return turnoverManager.overview(usernameParameter.orElse(null), limitParameter.orElse(15L),
				offsetParameter.orElse(0L), sort.orElse("username"),
				descending.orElse(false), filter);
	}

	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@GetMapping("/{id}")
	@Transactional
	public Turnover getById(@PathVariable("id") Long id) {
		if (!turnoverManager.exists(id)) {
			throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
		}

		return turnoverManager.get(id);
	}

	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@PatchMapping
	@Transactional
	public Turnover update(@RequestBody Turnover turnover) {
		Errors errors = new RequestBodyErrors(turnover);
		turnoverValidator.validate(turnover, errors);

		if (errors.hasErrors()) {
			throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
		}

		turnover.setUpdated(Instant.now());

		return turnoverManager.save(turnover);
	}

	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@DeleteMapping("/{id}")
	@Transactional
	public void deleteById(@PathVariable("id") Long id) {
		if (!turnoverManager.exists(id)) {
			throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
		}

		turnoverManager.deleteById(id);
	}
}
