package ru.nbch.indicsearchservice.controller;

import io.swagger.v3.oas.annotations.Operation;
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 jakarta.validation.Valid;
import java.util.Optional;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import ru.nbch.indicsearchservice.dto.request.AddSearchJobRequestDto;
import ru.nbch.indicsearchservice.dto.response.AddSearchJobResponseDto;
import ru.nbch.indicsearchservice.dto.response.JobStatusResponseDto;
import ru.nbch.indicsearchservice.exception.InternalException;
import ru.nbch.indicsearchservice.service.IndicSearchService;
import ru.nbch.indicsearchservice.service.SettingsService;

@RestController
@RequestMapping("/api/v1/")
public class IndicSearchController {
    private final IndicSearchService indicSearchService;
    private final SettingsService settingsService;

    public IndicSearchController(IndicSearchService indicSearchService,
                                 SettingsService settingsService) {
        this.indicSearchService = indicSearchService;
        this.settingsService = settingsService;
    }

    @Operation(summary = "Add new search job")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200",
            content = {
                @Content(mediaType = "application/json",
                    schema = @Schema(implementation = AddSearchJobResponseDto.class))
            },
            description = "Success")
    })
    @PostMapping("/add_search_job")
    public AddSearchJobResponseDto addSearchJob(@RequestBody @Valid AddSearchJobRequestDto request) {
        return indicSearchService.addSearchJob(request);
    }

    @Operation(summary = "Get job status")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200",
            content = {
                @Content(mediaType = "application/json",
                    schema = @Schema(implementation = JobStatusResponseDto.class))
            },
            description = "Success")
    })
    @GetMapping("/job_status/{id}")
    public JobStatusResponseDto getJobStatus(@PathVariable("id") Long id) {
        return indicSearchService.getJobStatus(id);
    }

    @Operation(summary = "Export data as JSON or EXCEL")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200",
            content = {
                @Content(mediaType = "application/json",
                    schema = @Schema(implementation = ResponseEntity.class))
            },
            description = "Success")
    })
    @GetMapping("/export/{id}")
    public ResponseEntity<?> export(@PathVariable("id") Long id,
                                    @RequestParam(name = "type", defaultValue = "JSON") String exportType) {
        return indicSearchService.export(id, exportType);
    }

    @Operation(summary = "Update local service settings")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "Success")
    })
    @GetMapping("/update_settings")
    public void updateSettings() {
        settingsService.updateLocalSettings();
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public InternalException handleValidationException(MethodArgumentNotValidException ex) {
        FieldError fieldError = ex.getBindingResult().getFieldErrors().getFirst();
        if (fieldError.getCodes() == null) {
            return new InternalException("Internal Server Error");
        }
        return switch (Optional.of(fieldError.getCodes()).orElse(new String[]{""})[0]) {
            case "NotNull.addSearchJobRequestDto.dataType" -> new InternalException("Data type should not be null");
            case "NotNull.addSearchJobRequestDto.searchParameter" -> new InternalException("Search parameter should not be null");
            case "NotBlank.addSearchJobRequestDto.searchValue" -> new InternalException("Search value should not be null");
            case "NotBlank.addSearchJobRequestDto.memberCode" -> new InternalException("Member code should not be null");
            case "Size.addSearchJobRequestDto.memberCode" -> new InternalException("Member code should contain at least 6 symbols");
            default -> new InternalException("Internal Server Error");
        };
    }
}
