package com.huimv.employment.common.util;

import com.huimv.employment.common.exception.BizException;
import com.huimv.employment.common.exception.ErrorCode;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 手机号校验、脱敏与哈希工具。
 * <p>
 * 本项目手机号处理规范（与技术方案 §7.5 一致）：
 * <ul>
 *   <li>数据库禁止存明文，使用 {@link AesUtils} 加密后写入 {@code mobile_enc}</li>
 *   <li>列表/日志展示使用 {@link #mask(String)} 脱敏值，如 138****8000</li>
 *   <li>Redis Key 使用 {@link #hash(String)} 哈希值，避免缓存中泄露明文</li>
 * </ul>
 * </p>
 */
public final class MobileUtils {

    /** 中国大陆手机号正则：1 开头，第二位 3-9，共 11 位 */
    private static final String MOBILE_PATTERN = "^1[3-9]\\d{9}$";

    private MobileUtils() {
    }

    /**
     * 校验手机号格式，不合法时抛出业务异常。
     *
     * @param mobile 待校验手机号
     * @throws BizException {@link ErrorCode#BAD_REQUEST}
     */
    public static void validate(String mobile) {
        if (mobile == null || !mobile.matches(MOBILE_PATTERN)) {
            throw new BizException(ErrorCode.BAD_REQUEST, "手机号格式不正确");
        }
    }

    /**
     * 生成手机号脱敏展示值。
     * <p>示例：13800138000 → 138****8000</p>
     *
     * @param mobile 明文手机号（会先校验格式）
     * @return 脱敏字符串，写入 fe_user.mobile_mask
     */
    public static String mask(String mobile) {
        validate(mobile);
        return mobile.substring(0, 3) + "****" + mobile.substring(7);
    }

    /**
     * 对手机号做 SHA-256 哈希，返回十六进制字符串。
     * <p>用于 Redis Key 组成（{@link com.huimv.employment.common.constant.RedisKeys}），
     * 避免在缓存中存储明文手机号。</p>
     *
     * @param mobile 明文手机号（会先校验格式）
     * @return 64 位十六进制哈希值
     */
    public static String hash(String mobile) {
        validate(mobile);
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] bytes = digest.digest(mobile.getBytes(StandardCharsets.UTF_8));
            return toHex(bytes);
        } catch (NoSuchAlgorithmException ex) {
            throw new IllegalStateException("SHA-256 not available", ex);
        }
    }

    private static String toHex(byte[] bytes) {
        StringBuilder builder = new StringBuilder(bytes.length * 2);
        for (byte value : bytes) {
            builder.append(String.format("%02x", value));
        }
        return builder.toString();
    }
}
