package org.brapi.test.BrAPITestServer.controller.geno;

import java.util.List;

import org.brapi.test.BrAPITestServer.controller.core.BrAPIController;
import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerException;
import org.brapi.test.BrAPITestServer.model.dto.geno.VariantSetAnalysisListResponse;
import org.brapi.test.BrAPITestServer.model.dto.geno.VariantSetAnalysisWriteRequest;
import org.brapi.test.BrAPITestServer.model.dto.geno.VariantSetAvailableFormatListResponse;
import org.brapi.test.BrAPITestServer.model.dto.geno.VariantSetAvailableFormatRecord;
import org.brapi.test.BrAPITestServer.model.dto.geno.VariantSetAvailableFormatWriteRequest;
import org.brapi.test.BrAPITestServer.model.dto.geno.VariantSetWriteRequest;
import org.brapi.test.BrAPITestServer.model.dto.geno.VariantWriteRequest;
import org.brapi.test.BrAPITestServer.service.geno.VariantService;
import org.brapi.test.BrAPITestServer.service.geno.VariantSetAnalysisService;
import org.brapi.test.BrAPITestServer.service.geno.VariantSetAvailableFormatService;
import org.brapi.test.BrAPITestServer.service.geno.VariantSetService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.model.geno.Analysis;
import io.swagger.model.geno.Variant;
import io.swagger.model.geno.VariantSet;
import io.swagger.model.geno.VariantSetResponse;
import io.swagger.model.geno.VariantSetsListResponse;
import io.swagger.model.geno.VariantSetsListResponseResult;
import io.swagger.model.geno.VariantSingleResponse;
import io.swagger.model.geno.VariantsListResponse;
import io.swagger.model.geno.VariantsListResponseResult;
import jakarta.servlet.http.HttpServletRequest;

@RestController
public class GenotypingVariantWriteController extends BrAPIController {

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

	private final VariantSetService variantSetService;
	private final VariantSetAnalysisService variantSetAnalysisService;
	private final VariantSetAvailableFormatService variantSetAvailableFormatService;
	private final VariantService variantService;
	private final HttpServletRequest request;

	@Autowired
	public GenotypingVariantWriteController(VariantSetService variantSetService,
			VariantSetAnalysisService variantSetAnalysisService,
			VariantSetAvailableFormatService variantSetAvailableFormatService, VariantService variantService,
			HttpServletRequest request) {
		this.variantSetService = variantSetService;
		this.variantSetAnalysisService = variantSetAnalysisService;
		this.variantSetAvailableFormatService = variantSetAvailableFormatService;
		this.variantService = variantService;
		this.request = request;
	}

	@CrossOrigin
	@RequestMapping(value = "/variantsets", produces = { "application/json" }, consumes = {
			"application/json" }, method = RequestMethod.POST)
	public ResponseEntity<VariantSetsListResponse> variantSetsPost(@RequestBody VariantSetWriteRequest body,
			@RequestHeader(value = "Authorization", required = false) String authorization)
			throws BrAPIServerException {
		log.debug("Request: " + request.getRequestURI());
		validateSecurityContext(request, "ROLE_USER");
		validateAcceptHeader(request);
		VariantSet data = variantSetService.saveVariantSet(body);
		return responseOK(new VariantSetsListResponse(), new VariantSetsListResponseResult(), List.of(data));
	}

	@CrossOrigin
	@RequestMapping(value = "/variantsets/{variantSetDbId}", produces = { "application/json" }, consumes = {
			"application/json" }, method = RequestMethod.PUT)
	public ResponseEntity<VariantSetResponse> variantSetsVariantSetDbIdPut(
			@PathVariable("variantSetDbId") String variantSetDbId, @RequestBody VariantSetWriteRequest body,
			@RequestHeader(value = "Authorization", required = false) String authorization)
			throws BrAPIServerException {
		log.debug("Request: " + request.getRequestURI());
		validateSecurityContext(request, "ROLE_USER");
		validateAcceptHeader(request);
		VariantSet data = variantSetService.updateVariantSet(variantSetDbId, body);
		return responseOK(new VariantSetResponse(), data);
	}

	@CrossOrigin
	@RequestMapping(value = "/variantsets/{variantSetDbId}", produces = {
			"application/json" }, method = RequestMethod.DELETE)
	public ResponseEntity<VariantSetResponse> variantSetsVariantSetDbIdDelete(
			@PathVariable("variantSetDbId") String variantSetDbId,
			@RequestHeader(value = "Authorization", required = false) String authorization)
			throws BrAPIServerException {
		log.debug("Request: " + request.getRequestURI());
		validateSecurityContext(request, "ROLE_USER");
		validateAcceptHeader(request);
		VariantSet data = variantSetService.deleteVariantSet(variantSetDbId);
		return responseOK(new VariantSetResponse(), data);
	}

	@CrossOrigin
	@RequestMapping(value = "/variantsets/{variantSetDbId}/analysis", produces = {
			"application/json" }, method = RequestMethod.GET)
	public ResponseEntity<VariantSetAnalysisListResponse> variantSetsVariantSetDbIdAnalysisGet(
			@PathVariable("variantSetDbId") String variantSetDbId,
			@RequestHeader(value = "Authorization", required = false) String authorization)
			throws BrAPIServerException {
		log.debug("Request: " + request.getRequestURI());
		validateSecurityContext(request, "ROLE_USER");
		validateAcceptHeader(request);
		List<Analysis> data = variantSetAnalysisService.findAnalysisByVariantSet(variantSetDbId);
		return responseOK(new VariantSetAnalysisListResponse(), new VariantSetAnalysisListResponse.Result(), data);
	}

	@CrossOrigin
	@RequestMapping(value = "/variantsets/{variantSetDbId}/analysis", produces = { "application/json" }, consumes = {
			"application/json" }, method = RequestMethod.POST)
	public ResponseEntity<VariantSetAnalysisListResponse> variantSetsVariantSetDbIdAnalysisPost(
			@PathVariable("variantSetDbId") String variantSetDbId, @RequestBody VariantSetAnalysisWriteRequest body,
			@RequestHeader(value = "Authorization", required = false) String authorization)
			throws BrAPIServerException {
		log.debug("Request: " + request.getRequestURI());
		validateSecurityContext(request, "ROLE_USER");
		validateAcceptHeader(request);
		Analysis data = variantSetAnalysisService.saveAnalysis(variantSetDbId, body);
		return responseOK(new VariantSetAnalysisListResponse(), new VariantSetAnalysisListResponse.Result(),
				List.of(data));
	}

	@CrossOrigin
	@RequestMapping(value = "/variantsets/{variantSetDbId}/analysis/{analysisDbId}", produces = {
			"application/json" }, consumes = { "application/json" }, method = RequestMethod.PUT)
	public ResponseEntity<VariantSetAnalysisListResponse> variantSetsVariantSetDbIdAnalysisAnalysisDbIdPut(
			@PathVariable("variantSetDbId") String variantSetDbId,
			@PathVariable("analysisDbId") String analysisDbId, @RequestBody VariantSetAnalysisWriteRequest body,
			@RequestHeader(value = "Authorization", required = false) String authorization)
			throws BrAPIServerException {
		log.debug("Request: " + request.getRequestURI());
		validateSecurityContext(request, "ROLE_USER");
		validateAcceptHeader(request);
		Analysis data = variantSetAnalysisService.updateAnalysis(variantSetDbId, analysisDbId, body);
		return responseOK(new VariantSetAnalysisListResponse(), new VariantSetAnalysisListResponse.Result(),
				List.of(data));
	}

	@CrossOrigin
	@RequestMapping(value = "/variantsets/{variantSetDbId}/analysis/{analysisDbId}", produces = {
			"application/json" }, method = RequestMethod.DELETE)
	public ResponseEntity<VariantSetAnalysisListResponse> variantSetsVariantSetDbIdAnalysisAnalysisDbIdDelete(
			@PathVariable("variantSetDbId") String variantSetDbId,
			@PathVariable("analysisDbId") String analysisDbId,
			@RequestHeader(value = "Authorization", required = false) String authorization)
			throws BrAPIServerException {
		log.debug("Request: " + request.getRequestURI());
		validateSecurityContext(request, "ROLE_USER");
		validateAcceptHeader(request);
		Analysis data = variantSetAnalysisService.deleteAnalysis(variantSetDbId, analysisDbId);
		return responseOK(new VariantSetAnalysisListResponse(), new VariantSetAnalysisListResponse.Result(),
				List.of(data));
	}

	@CrossOrigin
	@RequestMapping(value = "/variantsets/{variantSetDbId}/availableformats", produces = {
			"application/json" }, method = RequestMethod.GET)
	public ResponseEntity<VariantSetAvailableFormatListResponse> variantSetsVariantSetDbIdAvailableformatsGet(
			@PathVariable("variantSetDbId") String variantSetDbId,
			@RequestHeader(value = "Authorization", required = false) String authorization)
			throws BrAPIServerException {
		log.debug("Request: " + request.getRequestURI());
		validateSecurityContext(request, "ROLE_USER");
		validateAcceptHeader(request);
		List<VariantSetAvailableFormatRecord> data = variantSetAvailableFormatService
				.findFormatsByVariantSet(variantSetDbId);
		return responseOK(new VariantSetAvailableFormatListResponse(),
				new VariantSetAvailableFormatListResponse.Result(), data);
	}

	@CrossOrigin
	@RequestMapping(value = "/variantsets/{variantSetDbId}/availableformats", produces = { "application/json" },
			consumes = { "application/json" }, method = RequestMethod.POST)
	public ResponseEntity<VariantSetAvailableFormatListResponse> variantSetsVariantSetDbIdAvailableformatsPost(
			@PathVariable("variantSetDbId") String variantSetDbId,
			@RequestBody VariantSetAvailableFormatWriteRequest body,
			@RequestHeader(value = "Authorization", required = false) String authorization)
			throws BrAPIServerException {
		log.debug("Request: " + request.getRequestURI());
		validateSecurityContext(request, "ROLE_USER");
		validateAcceptHeader(request);
		VariantSetAvailableFormatRecord data = variantSetAvailableFormatService.saveFormat(variantSetDbId, body);
		return responseOK(new VariantSetAvailableFormatListResponse(),
				new VariantSetAvailableFormatListResponse.Result(), List.of(data));
	}

	@CrossOrigin
	@RequestMapping(value = "/variantsets/{variantSetDbId}/availableformats/{formatDbId}", produces = {
			"application/json" }, consumes = { "application/json" }, method = RequestMethod.PUT)
	public ResponseEntity<VariantSetAvailableFormatListResponse> variantSetsVariantSetDbIdAvailableformatsFormatDbIdPut(
			@PathVariable("variantSetDbId") String variantSetDbId, @PathVariable("formatDbId") String formatDbId,
			@RequestBody VariantSetAvailableFormatWriteRequest body,
			@RequestHeader(value = "Authorization", required = false) String authorization)
			throws BrAPIServerException {
		log.debug("Request: " + request.getRequestURI());
		validateSecurityContext(request, "ROLE_USER");
		validateAcceptHeader(request);
		VariantSetAvailableFormatRecord data = variantSetAvailableFormatService.updateFormat(variantSetDbId, formatDbId,
				body);
		return responseOK(new VariantSetAvailableFormatListResponse(),
				new VariantSetAvailableFormatListResponse.Result(), List.of(data));
	}

	@CrossOrigin
	@RequestMapping(value = "/variantsets/{variantSetDbId}/availableformats/{formatDbId}", produces = {
			"application/json" }, method = RequestMethod.DELETE)
	public ResponseEntity<VariantSetAvailableFormatListResponse> variantSetsVariantSetDbIdAvailableformatsFormatDbIdDelete(
			@PathVariable("variantSetDbId") String variantSetDbId, @PathVariable("formatDbId") String formatDbId,
			@RequestHeader(value = "Authorization", required = false) String authorization)
			throws BrAPIServerException {
		log.debug("Request: " + request.getRequestURI());
		validateSecurityContext(request, "ROLE_USER");
		validateAcceptHeader(request);
		VariantSetAvailableFormatRecord data = variantSetAvailableFormatService.deleteFormat(variantSetDbId, formatDbId);
		return responseOK(new VariantSetAvailableFormatListResponse(),
				new VariantSetAvailableFormatListResponse.Result(), List.of(data));
	}

	@CrossOrigin
	@RequestMapping(value = "/variants", produces = { "application/json" }, consumes = {
			"application/json" }, method = RequestMethod.POST)
	public ResponseEntity<VariantsListResponse> variantsPost(@RequestBody VariantWriteRequest body,
			@RequestHeader(value = "Authorization", required = false) String authorization)
			throws BrAPIServerException {
		log.debug("Request: " + request.getRequestURI());
		validateSecurityContext(request, "ROLE_USER");
		validateAcceptHeader(request);
		Variant data = variantService.saveVariant(body);
		return responseOK(new VariantsListResponse(), new VariantsListResponseResult(), List.of(data));
	}

	@CrossOrigin
	@RequestMapping(value = "/variants/{variantDbId}", produces = { "application/json" }, consumes = {
			"application/json" }, method = RequestMethod.PUT)
	public ResponseEntity<VariantSingleResponse> variantsVariantDbIdPut(
			@PathVariable("variantDbId") String variantDbId, @RequestBody VariantWriteRequest body,
			@RequestHeader(value = "Authorization", required = false) String authorization)
			throws BrAPIServerException {
		log.debug("Request: " + request.getRequestURI());
		validateSecurityContext(request, "ROLE_USER");
		validateAcceptHeader(request);
		Variant data = variantService.updateVariant(variantDbId, body);
		return responseOK(new VariantSingleResponse(), data);
	}

	@CrossOrigin
	@RequestMapping(value = "/variants/{variantDbId}", produces = {
			"application/json" }, method = RequestMethod.DELETE)
	public ResponseEntity<VariantSingleResponse> variantsVariantDbIdDelete(
			@PathVariable("variantDbId") String variantDbId,
			@RequestHeader(value = "Authorization", required = false) String authorization)
			throws BrAPIServerException {
		log.debug("Request: " + request.getRequestURI());
		validateSecurityContext(request, "ROLE_USER");
		validateAcceptHeader(request);
		Variant data = variantService.deleteVariant(variantDbId);
		return responseOK(new VariantSingleResponse(), data);
	}
}
