package com.airlock.iam.oauth2.infrastructure.exception.v3;

import com.airlock.iam.base.api.infrastructure.uri.ExternalUriInfo;
import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.core.misc.util.ExceptionUtils;
import com.airlock.iam.elog.api.EDefaultLogType;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.oauth2.infrastructure.validation.UnconfiguredAuthorizationServerException;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import jakarta.ws.rs.ext.ExceptionMapper;
import java.util.Optional;

@jakarta.ws.rs.ext.Provider
public final class OAuth2V3ExceptionMapper implements ExceptionMapper<Exception> {
   private static final ELogger LOG = ELoggerFactory.getLogger(OAuth2V3ExceptionMapper.class);
   private final Provider<ExternalUriInfo> uriInfo;

   @Inject
   public OAuth2V3ExceptionMapper(Provider<ExternalUriInfo> uriInfo) {
      this.uriInfo = uriInfo;
   }

   public Response toResponse(Exception exception) {
      if (exception instanceof NotFoundException) {
         LOG.debug("URL not found: " + LogUtil.logSafeQuote(((ExternalUriInfo)this.uriInfo.get()).getAbsolutePath()));
         return Response.status(Status.NOT_FOUND).build();
      } else if (exception instanceof UnconfiguredAuthorizationServerException) {
         LOG.debug("Invalid request: " + LogUtil.logSafeQuote(((ExternalUriInfo)this.uriInfo.get()).getAbsolutePath()) + ": " + exception.getMessage());
         return Response.status(Status.NOT_FOUND).build();
      } else {
         LOG.info(
            EDefaultLogType.GENERIC_LOG_TYPE,
            "Exception while handling OAuth 2.0 request "
               + LogUtil.logSafeQuote(((ExternalUriInfo)this.uriInfo.get()).getAbsolutePath())
               + this.getDetails(exception)
         );
         return Response.status(Status.INTERNAL_SERVER_ERROR).build();
      }
   }

   private String getDetails(Exception exception) {
      return Optional.ofNullable(ExceptionUtils.extractCause(exception)).map(message -> ": " + message).orElse("");
   }
}
