package com.tasteby.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.Reader;
import java.sql.Clob;
import java.util.*;
import java.util.stream.Collectors;

/**
 * JSON utility for handling Oracle CLOB JSON fields.
 */
public final class JsonUtil {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    private JsonUtil() {}

    public static String readClob(Object val) {
        if (val == null) return null;
        if (val instanceof String s) return s;
        if (val instanceof Clob clob) {
            try (Reader reader = clob.getCharacterStream()) {
                StringBuilder sb = new StringBuilder();
                char[] buf = new char[4096];
                int len;
                while ((len = reader.read(buf)) != -1) {
                    sb.append(buf, 0, len);
                }
                return sb.toString();
            } catch (Exception e) {
                return null;
            }
        }
        return val.toString();
    }

    public static List<String> parseStringList(Object raw) {
        String json = readClob(raw);
        if (json == null || json.isBlank()) return Collections.emptyList();
        try {
            return MAPPER.readValue(json, new TypeReference<>() {});
        } catch (Exception e) {
            return Collections.emptyList();
        }
    }

    public static Map<String, Object> parseMap(Object raw) {
        String json = readClob(raw);
        if (json == null || json.isBlank()) return Collections.emptyMap();
        try {
            return MAPPER.readValue(json, new TypeReference<>() {});
        } catch (Exception e) {
            // Plain text or malformed JSON (e.g. Python-style single quotes) → wrap as {"text": "..."}
            return Map.of("text", json.trim());
        }
    }

    /**
     * Convert Oracle uppercase column keys to lowercase (e.g. "ID" → "id", "CUISINE_TYPE" → "cuisine_type").
     */
    public static Map<String, Object> lowerKeys(Map<String, Object> row) {
        if (row == null) return null;
        var result = new LinkedHashMap<String, Object>(row.size());
        for (var entry : row.entrySet()) {
            result.put(entry.getKey().toLowerCase(), entry.getValue());
        }
        return result;
    }

    public static List<Map<String, Object>> lowerKeys(List<Map<String, Object>> rows) {
        if (rows == null) return null;
        return rows.stream().map(JsonUtil::lowerKeys).collect(Collectors.toList());
    }

    /**
     * Normalize evaluation to a valid JSON object string (e.g. {"text":"..."}).
     * Plain text is wrapped, already-valid JSON is returned as-is, and text is truncated to maxLen.
     */
    public static String normalizeEvaluation(String eval, int maxLen) {
        if (eval == null || eval.isBlank()) return null;
        String trimmed = eval.trim();
        if (trimmed.startsWith("{")) return trimmed;
        if (trimmed.length() > maxLen) {
            trimmed = trimmed.substring(0, maxLen);
        }
        return toJson(Map.of("text", trimmed));
    }

    public static String normalizeEvaluation(String eval) {
        return normalizeEvaluation(eval, 300);
    }

    public static String toJson(Object value) {
        try {
            return MAPPER.writeValueAsString(value);
        } catch (JsonProcessingException e) {
            return "{}";
        }
    }
}
