package tech.easyflow.datacenter.connector.support;

import tech.easyflow.common.web.exceptions.BusinessException;

import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.sql.SQLException;
import java.util.Locale;

public final class DatacenterConnectorExceptionSupport {

    public static final String SOURCE_UNAVAILABLE_MESSAGE = "当前连接不可用，请检查连接配置后重试";

    private DatacenterConnectorExceptionSupport() {
    }

    public static BusinessException wrapAccessException(String fallbackMessage, Exception ex) {
        if (ex instanceof BusinessException businessException && !isConnectionUnavailable(ex)) {
            return businessException;
        }
        if (isConnectionUnavailable(ex)) {
            return new BusinessException(SOURCE_UNAVAILABLE_MESSAGE);
        }
        return new BusinessException(fallbackMessage);
    }

    public static boolean isConnectionUnavailable(Throwable throwable) {
        Throwable current = throwable;
        while (current != null) {
            if (current instanceof ClassNotFoundException
                    || current instanceof ConnectException
                    || current instanceof NoRouteToHostException
                    || current instanceof SocketTimeoutException
                    || current instanceof UnknownHostException) {
                return true;
            }
            if (current instanceof SocketException socketException) {
                String socketMessage = lowerCase(socketException.getMessage());
                if (socketMessage.contains("broken pipe")
                        || socketMessage.contains("connection reset")
                        || socketMessage.contains("network is unreachable")) {
                    return true;
                }
            }
            if (current instanceof SQLException sqlException) {
                String sqlState = sqlException.getSQLState();
                String message = lowerCase(sqlException.getMessage());
                if ((sqlState != null && sqlState.startsWith("08"))
                        || message.contains("communications link failure")
                        || message.contains("connection refused")
                        || message.contains("connection attempt failed")
                        || message.contains("connect timed out")
                        || message.contains("i/o error")
                        || message.contains("io error")
                        || message.contains("the network adapter could not establish the connection")
                        || message.contains("unknown host")
                        || message.contains("access denied")
                        || message.contains("authentication failed")
                        || message.contains("login failed")
                        || message.contains("password authentication failed")
                        || message.contains("unknown database")
                        || message.contains("database does not exist")
                        || (message.contains("schema") && message.contains("does not exist"))
                        || message.contains("insufficient privilege")
                        || message.contains("permission denied")) {
                    return true;
                }
            }
            current = current.getCause();
        }
        return false;
    }

    private static String lowerCase(String message) {
        return message == null ? "" : message.toLowerCase(Locale.ROOT);
    }
}
