package cloud.nstart.terravault.ordinis.readapi.web;

import cloud.nstart.terravault.ordinis.readapi.service.RecordReadService.ScopeAccessDeniedException;
import cloud.nstart.terravault.ordinis.readapi.web.DictionaryReadController.BadBboxException;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.micrometer.tracing.Tracer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.time.OffsetDateTime;
import java.util.NoSuchElementException;

@RestControllerAdvice
public class ReadApiExceptionHandler {

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

  private final ObjectProvider<Tracer> tracerProvider;

  public ReadApiExceptionHandler(ObjectProvider<Tracer> tracerProvider) {
    this.tracerProvider = tracerProvider;
  }

  @JsonInclude(JsonInclude.Include.NON_NULL)
  public record ErrorBody(int status, String code, String message, String traceId, OffsetDateTime timestamp) {}

  @ExceptionHandler(NoSuchElementException.class)
  public ResponseEntity<ErrorBody> onNotFound(NoSuchElementException e) {
    return body(HttpStatus.NOT_FOUND, "not_found", e.getMessage());
  }

  @ExceptionHandler(ScopeAccessDeniedException.class)
  public ResponseEntity<ErrorBody> onScope(ScopeAccessDeniedException e) {
    return body(HttpStatus.FORBIDDEN, "scope_access_denied", e.getMessage());
  }

  @ExceptionHandler(IllegalArgumentException.class)
  public ResponseEntity<ErrorBody> onBadRequest(IllegalArgumentException e) {
    return body(HttpStatus.BAD_REQUEST, "bad_request", e.getMessage());
  }

  @ExceptionHandler(BadBboxException.class)
  public ResponseEntity<ErrorBody> onBadBbox(BadBboxException e) {
    return body(HttpStatus.BAD_REQUEST, "bad_bbox", e.getMessage());
  }

  @ExceptionHandler(Exception.class)
  public ResponseEntity<ErrorBody> onGeneric(Exception e) {
    log.error("Unhandled exception in read-api", e);
    return body(HttpStatus.INTERNAL_SERVER_ERROR, "internal_error", "Internal server error");
  }

  private ResponseEntity<ErrorBody> body(HttpStatus status, String code, String message) {
    return ResponseEntity.status(status)
        .body(new ErrorBody(status.value(), code, message, currentTraceId(), OffsetDateTime.now()));
  }

  private String currentTraceId() {
    Tracer tracer = tracerProvider.getIfAvailable();
    if (tracer == null) return null;
    var span = tracer.currentSpan();
    return span == null ? null : span.context().traceId();
  }
}
