package com.eactive.eai.rms.onl.apim.masking;

import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 메세지 본문/메신저ID 패턴 기반 마스킹 유틸 (발송 내역 화면 전용).
 *
 * <p>본문(message) 안에 섞여 있는 개인정보/인증정보를 패턴으로 찾아 마스킹하고,
 * 패턴 종류별로 색상 강조 {@code <span>} 으로 감싼 <b>안전한 HTML</b> 을 만든다.
 * 매칭되지 않은 영역과 마스킹 결과 모두 HTML escape 하므로 본문에 스크립트가 있어도 무력화된다.</p>
 *
 * <pre>
 *   이메일            test@gmail.com   → &lt;span class="mask-email"&gt;**st@gmail.com&lt;/span&gt;
 *   휴대폰(하이픈)     010-1234-5678    → &lt;span class="mask-phone"&gt;010-12**-56**&lt;/span&gt;
 *   6자리+ 숫자        123456           → &lt;span class="mask-digits"&gt;123***&lt;/span&gt; (앞 3자리 제외)
 *   메신저ID          kakao_abcd       → kakao_ab**  (뒤 2자리)
 * </pre>
 *
 * <p>실제 이메일/휴대폰 마스킹 규칙은 표준 구현
 * {@link com.eactive.eai.common.util.MaskingUtils}(elink-online-core)에 위임한다.</p>
 */
public final class MessagePatternMaskingUtils {

	private MessagePatternMaskingUtils() {}

	private static final int DIGITS_KEEP_HEAD = 3;

	/**
	 * 매칭 우선순위(이메일 &gt; 하이픈 휴대폰 &gt; 6자리+ 숫자)를 단일 패스로 보장하는 결합 정규식.
	 * 휴대폰 하이픈 형식이 "6자리 이상 숫자" 규칙에 이중 적용되지 않도록 한 Matcher 로 순회한다.
	 */
	private static final Pattern COMBINED = Pattern.compile(
			"(?<email>[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,})"
					+ "|(?<phone>01[016789]-\\d{3,4}-\\d{4})"
					+ "|(?<digits>\\d{6,})");

	/** 본문 → escape + 패턴별 마스킹/색상강조 span 이 적용된 안전 HTML 반환. */
	public static String maskAndHighlight(String raw) {
		if (raw == null || raw.isEmpty()) {
			return "";
		}
		Matcher m = COMBINED.matcher(raw);
		StringBuilder sb = new StringBuilder();
		int last = 0;
		while (m.find()) {
			sb.append(escapeHtml(raw.substring(last, m.start())));
			String token = m.group();
			if (m.group("email") != null) {
				sb.append(span("mask-email", com.eactive.eai.common.util.MaskingUtils.maskEmail(token)));
			} else if (m.group("phone") != null) {
				sb.append(span("mask-phone", com.eactive.eai.common.util.MaskingUtils.maskPhoneNumber(token)));
			} else {
				sb.append(span("mask-digits", maskKeepHead(token, DIGITS_KEEP_HEAD)));
			}
			last = m.end();
		}
		sb.append(escapeHtml(raw.substring(last)));
		return sb.toString();
	}

	/** 메신저 ID 마스킹: 뒤 2자리(2자 이하는 전체) 마스킹. */
	public static String maskMessengerId(String id) {
		if (id == null || id.isEmpty()) {
			return id;
		}
		if (id.length() <= 2) {
			return repeat('*', id.length());
		}
		return id.substring(0, id.length() - 2) + "**";
	}

	/** 앞 head 자리만 남기고 나머지를 '*' 로 마스킹. */
	private static String maskKeepHead(String digits, int head) {
		if (digits.length() <= head) {
			return digits;
		}
		return digits.substring(0, head) + repeat('*', digits.length() - head);
	}

	private static String span(String cls, String inner) {
		return "<span class=\"" + cls + "\">" + escapeHtml(inner) + "</span>";
	}

	/**
	 * 최소 HTML escape. {@code < > & " '} 만 변환하고 한글 등 비-ASCII 문자는 보존한다.
	 * (commons-lang {@code escapeHtml} 은 0x7F 초과 문자를 {@code &#NNN;} 로 변환해 한글이 깨지므로 직접 구현)
	 */
	private static String escapeHtml(String s) {
		if (s == null || s.isEmpty()) {
			return "";
		}
		StringBuilder sb = new StringBuilder(s.length());
		for (int i = 0; i < s.length(); i++) {
			char c = s.charAt(i);
			switch (c) {
				case '&': sb.append("&amp;"); break;
				case '<': sb.append("&lt;"); break;
				case '>': sb.append("&gt;"); break;
				case '"': sb.append("&quot;"); break;
				case '\'': sb.append("&#39;"); break;
				default: sb.append(c);
			}
		}
		return sb.toString();
	}

	private static String repeat(char c, int n) {
		if (n <= 0) {
			return "";
		}
		char[] a = new char[n];
		Arrays.fill(a, c);
		return new String(a);
	}
}
