package org.folio.rest.persist;

import io.vertx.pgclient.PgException;

import java.util.HashMap;
import java.util.Map;

public final class PgExceptionUtil {
  // https://www.postgresql.org/docs/current/static/errcodes-appendix.html
  static final String FOREIGN_KEY_VIOLATION = "23503";
  static final String UNIQUE_VIOLATION = "23505";
  static final String INVALID_TEXT_REPRESENTATION = "22P02";

  private PgExceptionUtil() {
    throw new UnsupportedOperationException("Cannot instantiate utility class.");
  }

  /**
   * Return the value for key in the
   *   {@link io.vertx.pgclient.PgException PgException}
   * @param throwable a Throwable or null
   * @param key
   * @return the value if throwable is a
   *   {@link io.vertx.pgclient.PgException PgException}
   *   and the key exists, null otherwise.
   */
  public static String get(Throwable throwable, Character key) {
    Map<Character,String> fields = getBadRequestFields(throwable);
    if (fields == null) {
      return null;
    }
    return fields.get(key);
  }

  /**
   * Check for foreign key violation.
   * @param throwable any Throwable or null
   * @return true if throwable is a
   *   {@link io.vertx.pgclient.PgException PgException}
   *   that reports a foreign key violation, false otherwise.
   */
  public static boolean isForeignKeyViolation(Throwable throwable) {
    return FOREIGN_KEY_VIOLATION.equals(get(throwable, 'C'));
  }

  /**
   * Check for unique violation.
   * @param throwable any Throwable or null
   * @return true if throwable is a
   *   {@link io.vertx.pgclient.PgException PgException}
   *   that reports a unique violation, false otherwise.
   */
  public static boolean isUniqueViolation(Throwable throwable) {
    return UNIQUE_VIOLATION.equals(get(throwable, 'C'));
  }

  /**
   * Check for invalid text representation.
   * @param throwable any Throwable or null
   * @return true if throwable is a
   *   {@link io.vertx.pgclient.PgException PgException}
   *   that reports an invalid text representation, false otherwise.
   */
  public static boolean isInvalidTextRepresentation(Throwable throwable) {
    return INVALID_TEXT_REPRESENTATION.equals(get(throwable, 'C'));
  }

  /**
   * If this throwable is an Exception thrown because of some PostgreSQL data
   * restriction (foreign key violation, invalid uuid, duplicate key) then
   * return some detail text of that Exception, otherwise return null.
   *
   * @param throwable - where to read the text from
   * @return detail text of the violation, or null if some other Exception
   */
  public static String badRequestMessage(Throwable throwable) {
    Map<Character,String> fields = getBadRequestFields(throwable);
    if (fields == null) {
      return null;
    }
    String sqlstate = fields.get('C');
    if (sqlstate == null) {
      return null;
    }
    String detail = fields.getOrDefault('D', "");
    String message = fields.getOrDefault('M', "");

    switch (sqlstate) {
    case FOREIGN_KEY_VIOLATION:
      // insert or update on table "item" violates foreign key constraint "item_permanentloantypeid_fkey":
      // Key (permanentloantypeid)=(5573df18-043f-4228-b108-483fd3a0cb57) is not present in table "loan_type".
    case UNIQUE_VIOLATION:
      // duplicate key value violates unique constraint "loan_type_unique_idx":
      // Key ((jsonb ->> 'name'::text))=(Can circulate) already exists.
      return message + ": " + detail;
    case INVALID_TEXT_REPRESENTATION:  // invalid input syntax for uuid: "1234"
      return message;
    default:
      return null;
    }
  }

  public static Map<Character, String> getBadRequestFields(Throwable throwable) {
    if (!(throwable instanceof PgException)) {
      return null;
    }
    Map<Character, String> map = new HashMap<>();
    map.put('M', ((PgException) throwable).getMessage());
    map.put('D', ((PgException) throwable).getDetail());
    map.put('C', ((PgException) throwable).getCode());
    return map;
  }
}

@@ -3965,11 +3965,313 @@
 map;%0A  %7D
+%0A%0A  /**%0A   * Constructor for PgException similar to the old postgres driver%0A   * @param map map of message, detail, code%0A   * @return%0A   */%0A  public static PgException createPgExceptionFromMap(Map%3CCharacter, String%3E map) %7B%0A    return new PgException(map.get('M'), null, map.get('C'), map.get('D'));%0A  %7D
 %0A%7D%0A

Add PgExceptionUtil.createPgExceptionFromMap