package egovframework.util;

import org.springframework.stereotype.Component;

import java.util.regex.Pattern;

/**
 * 데이터 유효성 검증 관련 공통 유틸리티 클래스
 */
@Component
public class ValidationUtil {

    /** 이메일 주소 정규식 패턴 */
    private static final Pattern EMAIL_PATTERN = 
            Pattern.compile("^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$");
    
    /** 한국 휴대폰 번호 정규식 패턴 (010-XXXX-XXXX 또는 010XXXXXXXX 형식) */
    private static final Pattern MOBILE_PHONE_PATTERN = 
            Pattern.compile("^01(?:0|1|[6-9])(?:-?\\d{3,4})?(?:-?\\d{4})$");
    
    /** 한국 일반 전화번호 정규식 패턴 (지역번호-국번-번호 형식) */
    private static final Pattern PHONE_PATTERN = 
            Pattern.compile("^(?:(?:\\d{2,3})|(?:\\d{2,3}-))(?:\\d{3,4}-\\d{4})$");
    
    /** 한국 우편번호 정규식 패턴 (5자리) */
    private static final Pattern ZIPCODE_PATTERN = 
            Pattern.compile("^\\d{5}$");
    
    /** 한국 주민등록번호 정규식 패턴 (XXXXXX-XXXXXXX 형식) */
    private static final Pattern RESIDENT_REGISTRATION_NUMBER_PATTERN = 
            Pattern.compile("^\\d{6}-?[1-4]\\d{6}$");
    
    /** 한국 사업자등록번호 정규식 패턴 (XXX-XX-XXXXX 형식) */
    private static final Pattern BUSINESS_REGISTRATION_NUMBER_PATTERN = 
            Pattern.compile("^\\d{3}-?\\d{2}-?\\d{5}$");
    
    /** IP 주소 정규식 패턴 (IPv4) */
    private static final Pattern IPV4_PATTERN = 
            Pattern.compile("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
    
    /** URL 정규식 패턴 */
    private static final Pattern URL_PATTERN = 
            Pattern.compile("^(https?|ftp)://[^\\s/$.?#].[^\\s]*$");
    
    /** 날짜 정규식 패턴 (YYYY-MM-DD 형식) */
    private static final Pattern DATE_PATTERN = 
            Pattern.compile("^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$");
    
    /** 시간 정규식 패턴 (HH:MM:SS 형식) */
    private static final Pattern TIME_PATTERN = 
            Pattern.compile("^([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$");
    
    /** 한글 정규식 패턴 */
    private static final Pattern KOREAN_PATTERN = 
            Pattern.compile("^[가-힣]+$");
    
    /** 영문자 정규식 패턴 */
    private static final Pattern ENGLISH_PATTERN = 
            Pattern.compile("^[a-zA-Z]+$");
    
    /** 영문자 및 숫자 정규식 패턴 */
    private static final Pattern ALPHANUMERIC_PATTERN = 
            Pattern.compile("^[a-zA-Z0-9]+$");
    
    /** 숫자 정규식 패턴 */
    private static final Pattern NUMERIC_PATTERN = 
            Pattern.compile("^[0-9]+$");
    
    /**
     * 이메일 주소 유효성 검증
     * @param email 검증할 이메일 주소
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isValidEmail(String email) {
        if (StringUtil.isEmpty(email)) {
            return false;
        }
        return EMAIL_PATTERN.matcher(email).matches();
    }
    
    /**
     * 한국 휴대폰 번호 유효성 검증
     * @param mobilePhone 검증할 휴대폰 번호
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isValidMobilePhone(String mobilePhone) {
        if (StringUtil.isEmpty(mobilePhone)) {
            return false;
        }
        return MOBILE_PHONE_PATTERN.matcher(mobilePhone).matches();
    }
    
    /**
     * 한국 일반 전화번호 유효성 검증
     * @param phone 검증할 전화번호
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isValidPhone(String phone) {
        if (StringUtil.isEmpty(phone)) {
            return false;
        }
        return PHONE_PATTERN.matcher(phone).matches();
    }
    
    /**
     * 한국 우편번호 유효성 검증
     * @param zipcode 검증할 우편번호
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isValidZipcode(String zipcode) {
        if (StringUtil.isEmpty(zipcode)) {
            return false;
        }
        return ZIPCODE_PATTERN.matcher(zipcode).matches();
    }
    
    /**
     * 한국 주민등록번호 유효성 검증 (형식만 검증, 실제 유효성은 검증하지 않음)
     * @param rrn 검증할 주민등록번호
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isValidResidentRegistrationNumber(String rrn) {
        if (StringUtil.isEmpty(rrn)) {
            return false;
        }
        return RESIDENT_REGISTRATION_NUMBER_PATTERN.matcher(rrn).matches();
    }
    
    /**
     * 한국 사업자등록번호 유효성 검증 (형식만 검증, 실제 유효성은 검증하지 않음)
     * @param brn 검증할 사업자등록번호
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isValidBusinessRegistrationNumber(String brn) {
        if (StringUtil.isEmpty(brn)) {
            return false;
        }
        return BUSINESS_REGISTRATION_NUMBER_PATTERN.matcher(brn).matches();
    }
    
    /**
     * IP 주소(IPv4) 유효성 검증
     * @param ipAddress 검증할 IP 주소
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isValidIpAddress(String ipAddress) {
        if (StringUtil.isEmpty(ipAddress)) {
            return false;
        }
        return IPV4_PATTERN.matcher(ipAddress).matches();
    }
    
    /**
     * URL 유효성 검증
     * @param url 검증할 URL
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isValidUrl(String url) {
        if (StringUtil.isEmpty(url)) {
            return false;
        }
        return URL_PATTERN.matcher(url).matches();
    }
    
    /**
     * 날짜 유효성 검증 (YYYY-MM-DD 형식)
     * @param date 검증할 날짜
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isValidDate(String date) {
        if (StringUtil.isEmpty(date)) {
            return false;
        }
        return DATE_PATTERN.matcher(date).matches();
    }
    
    /**
     * 시간 유효성 검증 (HH:MM:SS 또는 HH:MM 형식)
     * @param time 검증할 시간
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isValidTime(String time) {
        if (StringUtil.isEmpty(time)) {
            return false;
        }
        return TIME_PATTERN.matcher(time).matches();
    }
    
    /**
     * 한글 유효성 검증
     * @param text 검증할 문자열
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isKorean(String text) {
        if (StringUtil.isEmpty(text)) {
            return false;
        }
        return KOREAN_PATTERN.matcher(text).matches();
    }
    
    /**
     * 영문자 유효성 검증
     * @param text 검증할 문자열
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isEnglish(String text) {
        if (StringUtil.isEmpty(text)) {
            return false;
        }
        return ENGLISH_PATTERN.matcher(text).matches();
    }
    
    /**
     * 영문자 및 숫자 유효성 검증
     * @param text 검증할 문자열
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isAlphanumeric(String text) {
        if (StringUtil.isEmpty(text)) {
            return false;
        }
        return ALPHANUMERIC_PATTERN.matcher(text).matches();
    }
    
    /**
     * 숫자 유효성 검증
     * @param text 검증할 문자열
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isNumeric(String text) {
        if (StringUtil.isEmpty(text)) {
            return false;
        }
        return NUMERIC_PATTERN.matcher(text).matches();
    }
    
    /**
     * 비밀번호 복잡성 검증 (영문 대소문자, 숫자, 특수문자 포함 8자 이상)
     * @param password 검증할 비밀번호
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isValidPassword(String password) {
        if (StringUtil.isEmpty(password) || password.length() < 8) {
            return false;
        }
        
        boolean hasUpperCase = false;
        boolean hasLowerCase = false;
        boolean hasDigit = false;
        boolean hasSpecialChar = false;
        
        for (char c : password.toCharArray()) {
            if (Character.isUpperCase(c)) {
                hasUpperCase = true;
            } else if (Character.isLowerCase(c)) {
                hasLowerCase = true;
            } else if (Character.isDigit(c)) {
                hasDigit = true;
            } else if (!Character.isLetterOrDigit(c)) {
                hasSpecialChar = true;
            }
        }
        
        return hasUpperCase && hasLowerCase && hasDigit && hasSpecialChar;
    }
    
    /**
     * 문자열 길이 검증
     * @param text 검증할 문자열
     * @param minLength 최소 길이
     * @param maxLength 최대 길이
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isValidLength(String text, int minLength, int maxLength) {
        if (text == null) {
            return minLength <= 0;
        }
        int length = text.length();
        return length >= minLength && length <= maxLength;
    }
    
    /**
     * 주민등록번호 유효성 검증 (체크섬 포함)
     * @param rrn 검증할 주민등록번호 (XXXXXX-XXXXXXX 형식)
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isValidResidentRegistrationNumberWithChecksum(String rrn) {
        if (!isValidResidentRegistrationNumber(rrn)) {
            return false;
        }
        
        // 하이픈 제거
        rrn = rrn.replace("-", "");
        
        // 가중치 배열
        int[] weights = {2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5};
        
        // 합계 계산
        int sum = 0;
        for (int i = 0; i < 12; i++) {
            sum += (rrn.charAt(i) - '0') * weights[i];
        }
        
        // 체크섬 계산
        int checksum = (11 - (sum % 11)) % 10;
        
        // 마지막 자리와 체크섬 비교
        return checksum == (rrn.charAt(12) - '0');
    }
    
    /**
     * 사업자등록번호 유효성 검증 (체크섬 포함)
     * @param brn 검증할 사업자등록번호 (XXX-XX-XXXXX 형식)
     * @return 유효하면 true, 그렇지 않으면 false
     */
    public static boolean isValidBusinessRegistrationNumberWithChecksum(String brn) {
        if (!isValidBusinessRegistrationNumber(brn)) {
            return false;
        }
        
        // 하이픈 제거
        brn = brn.replace("-", "");
        
        // 가중치 배열
        int[] weights = {1, 3, 7, 1, 3, 7, 1, 3, 5};
        
        // 합계 계산
        int sum = 0;
        for (int i = 0; i < 9; i++) {
            sum += (brn.charAt(i) - '0') * weights[i];
        }
        
        // 체크섬 계산
        sum += ((brn.charAt(8) - '0') * 5) / 10;
        int checksum = (10 - (sum % 10)) % 10;
        
        // 마지막 자리와 체크섬 비교
        return checksum == (brn.charAt(9) - '0');
    }
}