package egovframework.util;

import org.springframework.stereotype.Component;

/**
 * 문자열 관련 공통 유틸리티 클래스
 */
@Component
public class StringUtil {

    /**
     * 문자열이 null이거나 빈 문자열인지 확인
     * @param str 검사할 문자열
     * @return null이거나 빈 문자열이면 true, 그렇지 않으면 false
     */
    public static boolean isEmpty(String str) {
        return str == null || str.isEmpty();
    }
    
    /**
     * 문자열이 null이 아니고 빈 문자열이 아닌지 확인
     * @param str 검사할 문자열
     * @return null이 아니고 빈 문자열이 아니면 true, 그렇지 않으면 false
     */
    public static boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }
    
    /**
     * 문자열이 null이거나 빈 문자열이거나 공백 문자로만 이루어져 있는지 확인
     * @param str 검사할 문자열
     * @return null이거나 빈 문자열이거나 공백 문자로만 이루어져 있으면 true, 그렇지 않으면 false
     */
    public static boolean isBlank(String str) {
        if (isEmpty(str)) {
            return true;
        }
        for (int i = 0; i < str.length(); i++) {
            if (!Character.isWhitespace(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * 문자열이 null이 아니고 빈 문자열이 아니고 공백 문자로만 이루어져 있지 않은지 확인
     * @param str 검사할 문자열
     * @return null이 아니고 빈 문자열이 아니고 공백 문자로만 이루어져 있지 않으면 true, 그렇지 않으면 false
     */
    public static boolean isNotBlank(String str) {
        return !isBlank(str);
    }
    
    /**
     * 문자열의 앞뒤 공백을 제거
     * @param str 처리할 문자열
     * @return 앞뒤 공백이 제거된 문자열, null이면 null 반환
     */
    public static String trim(String str) {
        return str == null ? null : str.trim();
    }
    
    /**
     * 문자열이 null이면 빈 문자열 반환, 그렇지 않으면 원래 문자열 반환
     * @param str 처리할 문자열
     * @return null이면 빈 문자열, 그렇지 않으면 원래 문자열
     */
    public static String nullToEmpty(String str) {
        return str == null ? "" : str;
    }
    
    /**
     * 문자열이 null이거나 빈 문자열이면 기본값 반환, 그렇지 않으면 원래 문자열 반환
     * @param str 처리할 문자열
     * @param defaultValue 기본값
     * @return null이거나 빈 문자열이면 기본값, 그렇지 않으면 원래 문자열
     */
    public static String defaultIfEmpty(String str, String defaultValue) {
        return isEmpty(str) ? defaultValue : str;
    }
    
    /**
     * 문자열이 null이거나 빈 문자열이거나 공백 문자로만 이루어져 있으면 기본값 반환, 그렇지 않으면 원래 문자열 반환
     * @param str 처리할 문자열
     * @param defaultValue 기본값
     * @return null이거나 빈 문자열이거나 공백 문자로만 이루어져 있으면 기본값, 그렇지 않으면 원래 문자열
     */
    public static String defaultIfBlank(String str, String defaultValue) {
        return isBlank(str) ? defaultValue : str;
    }
    
    /**
     * 문자열의 좌측에서 지정된 길이만큼 문자열 추출
     * @param str 처리할 문자열
     * @param len 추출할 길이
     * @return 추출된 문자열, null이면 null 반환
     */
    public static String left(String str, int len) {
        if (str == null) {
            return null;
        }
        if (len < 0) {
            return "";
        }
        if (str.length() <= len) {
            return str;
        }
        return str.substring(0, len);
    }
    
    /**
     * 문자열의 우측에서 지정된 길이만큼 문자열 추출
     * @param str 처리할 문자열
     * @param len 추출할 길이
     * @return 추출된 문자열, null이면 null 반환
     */
    public static String right(String str, int len) {
        if (str == null) {
            return null;
        }
        if (len < 0) {
            return "";
        }
        if (str.length() <= len) {
            return str;
        }
        return str.substring(str.length() - len);
    }
    
    /**
     * 문자열에서 특정 문자열을 다른 문자열로 모두 치환
     * @param str 처리할 문자열
     * @param searchStr 찾을 문자열
     * @param replaceStr 치환할 문자열
     * @return 치환된 문자열, null이면 null 반환
     */
    public static String replace(String str, String searchStr, String replaceStr) {
        if (isEmpty(str) || isEmpty(searchStr) || replaceStr == null) {
            return str;
        }
        return str.replace(searchStr, replaceStr);
    }
    
    /**
     * 문자열 내의 HTML 특수 문자를 이스케이프 처리
     * @param str 처리할 문자열
     * @return 이스케이프 처리된 문자열, null이면 null 반환
     */
    public static String escapeHtml(String str) {
        if (str == null) {
            return null;
        }
        return str.replace("&", "&amp;")
                 .replace("<", "&lt;")
                 .replace(">", "&gt;")
                 .replace("\"", "&quot;")
                 .replace("'", "&#39;");
    }
    
    /**
     * 문자열 내의 줄바꿈 문자를 HTML <br> 태그로 변환
     * @param str 처리할 문자열
     * @return 변환된 문자열, null이면 null 반환
     */
    public static String nl2br(String str) {
        if (str == null) {
            return null;
        }
        return str.replace("\r\n", "<br>")
                 .replace("\n", "<br>")
                 .replace("\r", "<br>");
    }
    
    /**
     * 문자열이 지정된 접두사로 시작하는지 확인
     * @param str 검사할 문자열
     * @param prefix 접두사
     * @return 지정된 접두사로 시작하면 true, 그렇지 않으면 false
     */
    public static boolean startsWith(String str, String prefix) {
        return str != null && prefix != null && str.startsWith(prefix);
    }
    
    /**
     * 문자열이 지정된 접미사로 끝나는지 확인
     * @param str 검사할 문자열
     * @param suffix 접미사
     * @return 지정된 접미사로 끝나면 true, 그렇지 않으면 false
     */
    public static boolean endsWith(String str, String suffix) {
        return str != null && suffix != null && str.endsWith(suffix);
    }
    
    /**
     * 문자열을 지정된 길이로 자르고 생략 부호를 추가
     * @param str 처리할 문자열
     * @param maxLength 최대 길이
     * @param suffix 생략 부호 (예: "...")
     * @return 처리된 문자열, null이면 null 반환
     */
    public static String abbreviate(String str, int maxLength, String suffix) {
        if (str == null) {
            return null;
        }
        if (str.length() <= maxLength) {
            return str;
        }
        if (suffix == null) {
            suffix = "";
        }
        int suffixLength = suffix.length();
        if (maxLength <= suffixLength) {
            return suffix;
        }
        return str.substring(0, maxLength - suffixLength) + suffix;
    }
    
    /**
     * 문자열의 UTF-8 바이트 길이를 계산한다.
     * 한글 문자는 3바이트, 영문/숫자는 1바이트로 계산한다.
     *
     * @param str 바이트 길이를 계산할 문자열
     * @return 계산된 바이트 길이, null이면 0 반환
     */
    public static int calculateUtf8ByteLength(String str) {
        if (str == null || str.isEmpty()) {
            return 0;
        }

        int byteLength = 0;
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);

            // 한글 유니코드 범위 확인
            if ((c >= 0xAC00 && c <= 0xD7A3) || (c >= 0x3131 && c <= 0x318E)) {
                byteLength += 3; // 한글은 3바이트
            } else {
                byteLength += 1; // 영문/숫자는 1바이트
            }
        }

        return byteLength;
    }

    /**
     * null 안전 처리 (null을 빈 문자열로 변환)
     * @param value 처리할 문자열
     * @return null이면 빈 문자열, 그렇지 않으면 원래 문자열
     */
    public static String nvl(String value) {
        return value != null ? value : "";
    }

    /**
     * 주민번호 마스킹 (뒤 7자리 마스킹)
     * @param idecno 주민번호
     * @return 마스킹된 주민번호 (앞 6자리만 보이고 뒤는 *******)
     */
    public static String maskIdecno(String idecno) {
        if (idecno == null || idecno.length() < 7) {
            return idecno != null ? idecno : "";
        }
        String front = idecno.substring(0, Math.min(6, idecno.length()));
        return front + "*******";
    }

    /**
     * 문자열 추가 헬퍼 (값이 있을 때만 StringBuilder에 추가)
     * @param sb StringBuilder 객체
     * @param label 레이블
     * @param value 값
     */
    public static void appendIfNotEmpty(StringBuilder sb, String label, String value) {
        if (value != null && !value.isEmpty()) {
            if (sb.length() > 0) {
                sb.append(", ");
            }
            sb.append(label).append(": ").append(value);
        }
    }
}