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

import cz.muni.fi.pa165.core.helpers.exceptions.EntityConflictException;
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.company.CompanyCreateDto;
import cz.muni.fi.pa165.model.dto.company.CompanyDto;
import cz.muni.fi.pa165.model.dto.company.CompanyUpdateDto;
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.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.persistence.EntityNotFoundException;
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.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

@RestController
@RequestMapping("/api/company")
@Tag(name = "Company", description = "Device API")

public class CompanyController {
	private final CompanyFacade companyFacade;

	@Autowired
	public CompanyController(CompanyFacade companyFacade) {
		this.companyFacade = companyFacade;
	}

	@Operation(summary = "Find all companies with pagination or without")
	@ApiResponses(
			value = {
					@ApiResponse(responseCode = "200", description = "List of companies", content = {
							@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = Result.class))
					})
			}
	)
	@GetMapping("/all")
	public Result<CompanyDto> 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 companyFacade.findAllPageable(pageWithElements);
	}

	@Operation(summary = "Find company by id")
	@ApiResponses(
			value = {
					@ApiResponse(responseCode = "200", description = "Company found", content = {
							@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = CompanyDto.class))
					}),
					@ApiResponse(responseCode = "404", description = "Company not found", content = @Content)
			}
	)
	@GetMapping("/{id}")
	public CompanyDto findById(@PathVariable @Parameter(description = "The id of the company.") String id) {
		try {
			return companyFacade.findById(id);
		} catch (EntityNotFoundException ex) {
			throw new ResponseStatusException(HttpStatus.NOT_FOUND, ex.getMessage());
		}
	}

	@PostMapping
	@Operation(summary = "Create a new company")
	@ApiResponse(responseCode = "201", description = "The newly created company",
			content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
					schema = @Schema(implementation = CompanyDto.class)))
	@ApiResponse(responseCode = "409", description = "Company with the same name already exists", content = @Content)
	public ResponseEntity<CompanyDto> create(@RequestBody @Valid CompanyCreateDto companyCreateDto) {
		try {
			return ResponseEntity.status(HttpStatus.CREATED).body(companyFacade.create(companyCreateDto));
		} catch (EntityConflictException ex) {
			throw new ResponseStatusException(HttpStatus.CONFLICT, ex.getMessage());
		}
	}

	@PutMapping("/{id}")
	@Operation(summary = "Update a company by ID")
	@ApiResponse(responseCode = "200", description = "The updated company",
			content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
					schema = @Schema(implementation = CompanyDto.class)))
	@ApiResponse(responseCode = "409", description = "Company with the same name already exists", content = @Content)
	@ApiResponse(responseCode = "404", description = "Company not found", content = @Content)
	public CompanyDto updateById(@PathVariable @Parameter(description = "The id of the company.") String id,
								 @RequestBody @Valid CompanyUpdateDto companyUpdateDto) {
		try {
			return companyFacade.updateById(companyUpdateDto, id);
		} catch (EntityConflictException ex) {
			throw new ResponseStatusException(HttpStatus.CONFLICT, ex.getMessage());
		}
	}

	@DeleteMapping("/{id}")
	@Operation(summary = "Delete a company by ID")
	@ApiResponse(responseCode = "200", description = "The deleted company",
			content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
					schema = @Schema(implementation = CompanyDto.class)))
	@ApiResponse(responseCode = "404", description = "Company not found", content = @Content)
	@ApiResponse(responseCode = "422", description = "Company could not be deleted", content = @Content)
	@ApiResponse(responseCode = "505", description = "Error occurred", content = @Content)
	public ResponseEntity<?> deleteById(@PathVariable @Parameter(description = "The id of the company.") String id) {
		try {
			return ResponseEntity.status(HttpStatus.OK).body(companyFacade.deleteById(id));
		} catch (EntityNotFoundException ex) {
			return ResponseEntity.status(HttpStatus.NOT_FOUND)
					.body(ex.getMessage());
		} catch (EntityDeletionException ex) {
			return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY)
					.body(ex.getMessage());
		} catch (Exception e) {
			return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
					.body("Error occurred");
		}
	}
}
