package com.eactive.ext.kjb.ums.gson;

import com.google.gson.*;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

public class GsonUtil {
    /** 한 번만 생성해 두고 재사용 */
    private static final Gson GSON = new GsonBuilder()
            .setPrettyPrinting()          // 필요 시 포맷 옵션
            .create();

    private GsonUtil() {
        /* 인스턴스 생성 금지 */
    }

    /* ------------------------------------------------------------------ *
     * 1. 객체 ↔ JSON 문자열
     * ------------------------------------------------------------------ */
    /** 객체 → JSON 문자열 */
    public static String toJson(Object src) {
        return GSON.toJson(src);
    }

    /** JSON 문자열 → 객체 */
    public static <T> T fromJson(String json, Class<T> clazz) {
        return GSON.fromJson(json, clazz);
    }

    /* ------------------------------------------------------------------ *
     * 2. 객체 ↔ JsonElement
     * ------------------------------------------------------------------ */
    /** 객체 → JsonElement (Gson 내부 표현) */
    public static JsonElement toJsonElement(Object src) {
        return GSON.toJsonTree(src);
    }

    /** JsonElement → 객체 */
    public static <T> T fromJsonElement(JsonElement json, Class<T> clazz) {
        return GSON.fromJson(json, clazz);
    }

    /* ------------------------------------------------------------------ *
     * 3. JSON 문자열 ↔ JsonObject
     * ------------------------------------------------------------------ */
    /** JSON 문자열 → JsonObject (정상적인 객체만 허용) */
    public static JsonObject fromJsonObject(String json) {
        JsonElement elem = GSON.fromJson(json, JsonElement.class);
        if (!elem.isJsonObject()) {
            throw new IllegalArgumentException("JSON 문자열이 JsonObject 가 아닙니다: " + json);
        }
        return elem.getAsJsonObject();
    }

    /** JsonObject → JSON 문자열 (정렬 옵션 없이) */
    public static String toJsonString(JsonObject jsonObj) {
        return GSON.toJson(jsonObj);
    }

    /* ------------------------------------------------------------------ *
     * 4. JSON 문자열 ↔ List<T>
     * ------------------------------------------------------------------ */
    /** JSON 문자열 → List&lt;T&gt;  */
    public static <T> List<T> fromJsonList(String json, Class<T> clazz) {
        // ParameterizedType 으로 List<T> 를 명시
        Type listType = new ParameterizedType() {
            @Override public Type[] getActualTypeArguments() { return new Type[]{clazz}; }
            @Override public Type getRawType()           { return List.class; }
            @Override public Type getOwnerType()         { return null; }
        };
        return GSON.fromJson(json, listType);
    }

    /* ------------------------------------------------------------------ *
     * 5. 기타 (예시: JsonArray ↔ List<T>)
     * ------------------------------------------------------------------ */
    /** JsonArray → List&lt;T&gt;  */
    public static <T> List<T> fromJsonArray(JsonArray array, Class<T> clazz) {
        return GSON.fromJson(array, new TypeToken<List<T>>(){}.getType());
    }

    /** List&lt;T&gt; → JsonArray */
    public static <T> JsonArray toJsonArray(List<T> list) {
        return GSON.toJsonTree(list).getAsJsonArray();
    }

    /**
     * JSON 문자열을 JsonObject 로 변환
     *
     * @param json  유효한 JSON 객체 문자열 (예: {"name":"John","age":30})
     * @return JsonObject 인스턴스
     * @throws IllegalArgumentException  JSON 문자열이 객체가 아닐 경우
     */
    public static JsonObject toJsonObject(String json) {
        // 먼저 JsonElement 로 파싱
        JsonElement element = GSON.fromJson(json, JsonElement.class);

        // 객체인지 검사
        if (!element.isJsonObject()) {
            throw new IllegalArgumentException(
                    "Provided JSON string is not a JsonObject: " + json);
        }

        // JsonObject 로 캐스팅 후 반환
        return element.getAsJsonObject();
    }

    /**
     * 일반 Java 객체 → JsonObject
     *
     * @param src  변환할 객체 (Map, POJO 등)
     * @return JsonObject 인스턴스
     * @throws IllegalArgumentException 객체가 JsonObject 로 변환될 수 없을 때
     */
    public static JsonObject toJsonObject(Object src) {
        // 객체를 JsonElement 로 변환
        JsonElement element = GSON.toJsonTree(src);

        // 객체인지 검사 (Map, POJO 등은 JsonObject 가 됨)
        if (!element.isJsonObject()) {
            throw new IllegalArgumentException(
                    "Provided object cannot be represented as a JsonObject: "
                            + src.getClass().getName());
        }

        return element.getAsJsonObject();
    }
}
