package com.aps.common.util;

import java.util.Arrays;
import java.util.List;

/**
 * Keeps client error messages short and business-readable.
 */
public final class ExceptionMessageUtil {

    private static final int MAX_CLIENT_MESSAGE_LENGTH = 180;

    private static final List<String> TECHNICAL_MARKERS = Arrays.asList(
            "Exception",
            "exception",
            "NullPointer",
            "Cannot invoke",
            "ClassCast",
            "NumberFormatException",
            "Index ",
            "out of bounds",
            "SQL",
            "ORA-",
            "JDBC",
            "MyBatis",
            "PreparedStatement",
            "ResultSet",
            "StackTrace",
            "nested exception",
            "java.",
            "javax.",
            "org.",
            "com.",
            "###"
    );

    private ExceptionMessageUtil() {
    }

    public static String toClientMessage(Throwable throwable, String fallback) {
        return cleanMessage(firstMessage(throwable), fallback);
    }

    public static String cleanMessage(String message, String fallback) {
        String safeFallback = isBlank(fallback) ? "系统处理失败，请稍后重试或联系管理员" : fallback;
        if (isBlank(message)) {
            return safeFallback;
        }

        String normalized = normalize(message);
        normalized = stripAfter(normalized, "; nested exception is");
        normalized = stripAfter(normalized, "nested exception is");
        normalized = stripAfter(normalized, "###");

        if (isBlank(normalized) || looksTechnical(normalized)) {
            return safeFallback;
        }

        if (normalized.length() > MAX_CLIENT_MESSAGE_LENGTH) {
            return normalized.substring(0, MAX_CLIENT_MESSAGE_LENGTH) + "...";
        }
        return normalized;
    }

    private static String firstMessage(Throwable throwable) {
        Throwable current = throwable;
        while (current != null) {
            if (!isBlank(current.getMessage())) {
                return current.getMessage();
            }
            current = current.getCause();
        }
        return null;
    }

    private static String normalize(String message) {
        return message.replace('\r', ' ')
                .replace('\n', ' ')
                .replace('\t', ' ')
                .replaceAll("\\s+", " ")
                .trim();
    }

    private static String stripAfter(String message, String marker) {
        int index = message.indexOf(marker);
        if (index < 0) {
            return message;
        }
        return message.substring(0, index).trim();
    }

    private static boolean looksTechnical(String message) {
        if (message.contains(":\\") || message.contains(":/")) {
            return true;
        }
        for (String marker : TECHNICAL_MARKERS) {
            if (message.contains(marker)) {
                return true;
            }
        }
        return false;
    }

    private static boolean isBlank(String value) {
        return value == null || value.trim().isEmpty();
    }
}
