package cz.muni.fi.pa165.core.metrics;

import cz.muni.fi.pa165.core.helpers.exceptions.EntityDeletionException;
import cz.muni.fi.pa165.model.dto.common.Result;
import cz.muni.fi.pa165.model.dto.metrics.MetricsCreateDto;
import cz.muni.fi.pa165.model.dto.metrics.MetricsDto;
import cz.muni.fi.pa165.model.dto.metrics.MetricsUpdateDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.PositiveOrZero;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.function.EntityResponse;

import java.util.List;

@RestController
@RequestMapping("/api/metric")
@Tag(name = "Metric", description = "Metric API")
public class MetricsController {
	private final MetricsFacade metricsFacade;

	@Autowired
	public MetricsController(MetricsFacade metricsFacade) {
		this.metricsFacade = metricsFacade;
	}

	@Operation(summary = "Find all metrics with pagination or without", responses = {
			@ApiResponse(responseCode = "200", description = "List of metrics", content = {
					@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = Result.class))
			})
	})
	@GetMapping
	public Result<MetricsDto> findAll(@Parameter(description = "Page number of results to retrieve") @RequestParam(defaultValue = "0", required = false) @PositiveOrZero int page,
									@Parameter(description = "Page size of results to retrieve") @RequestParam(defaultValue = "-1", required = false) int pageSize) {
		if(pageSize < 0)
			pageSize = 10;
		Pageable pageWithElements = PageRequest.of(page, pageSize);
		System.out.println(pageWithElements.getClass());
		return metricsFacade.findAllPageable(pageWithElements);
	}

	@Operation(summary = "Find metric by ID", description = "Returns the metric with the specified ID.")
	@GetMapping("/{id}")
	@ApiResponse(responseCode = "200", description = "Successfully retrieved the metric.")
	@ApiResponse(responseCode = "404", description = "Metric not found.")
	public MetricsDto findById(@PathVariable @Parameter(description = "The ID of the metric to retrieve.") String id) {
		return metricsFacade.findById(id);
	}

	@Operation(summary = "Create metric", description = "Creates a new metric.")
	@PostMapping
	@ApiResponse(responseCode = "201", description = "Successfully created a new metric.")
	@ApiResponse(responseCode = "404", description = "House/SmartMeter not found.")
	public ResponseEntity<MetricsDto> create(@RequestBody @Valid MetricsCreateDto metricsCreateDto) {
		return ResponseEntity.status(HttpStatus.CREATED).body(metricsFacade.create(metricsCreateDto));
	}

	@Operation(summary = "Update metric", description = "Updates the metric with the specified ID.")
	@PutMapping("/{id}")
	@ApiResponse(responseCode = "200", description = "Successfully updated the metric.")
	@ApiResponse(responseCode = "404", description = "Metric/House/SmartMeter not found.")
	public MetricsDto updateById(@PathVariable @Parameter(description = "The ID of the metric to update.") String id,
								 @RequestBody @Valid MetricsUpdateDto metricsUpdateDto) {
		return metricsFacade.updateById(metricsUpdateDto, id);
	}

	@Operation(summary = "Delete metric", description = "Deletes the metric with the specified ID.")
	@DeleteMapping("/{id}")
	@ApiResponse(responseCode = "200", description = "Successfully deleted the metric.")
	@ApiResponse(responseCode = "404", description = "Metric not found.")
	@ApiResponse(responseCode = "422", description = "Metrics could not be deleted", content = @Content)
	@ApiResponse(responseCode = "505", description = "Error occurred", content = @Content)
	public ResponseEntity<?> deleteById(@PathVariable @Parameter(description = "The ID of the metric to delete.") String id) {
		try {
			return ResponseEntity.status(HttpStatus.OK).body(metricsFacade.deleteById(id));
		} catch (EntityDeletionException ex) {
			return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY)
					.body(ex.getMessage());
		} catch (Exception e) {
			return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
					.body("Error occured");
		}
	}
}
