package com.mosquito.project.service;

import com.mosquito.project.permission.PermissionCheckService;
import com.mosquito.project.persistence.entity.SystemConfigEntity;
import com.mosquito.project.persistence.repository.SystemConfigRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import jakarta.annotation.PostConstruct;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

/**
 * 敏感数据脱敏服务
 * 根据用户权限决定是否显示明文或脱敏数据
 * 支持：手机号、身份证、银行卡、邮箱
 *
 * 支持配置化驱动：
 * - 通过 system_config 表配置敏感字段规则
 * - config_key 格式: sensitive.mask.{type} (如 sensitive.mask.phone)
 * - config_value: 脱敏规则 (如 "3-4" 表示保留前3位和后4位)
 */
@Service
public class SensitiveMaskingService {

    private static final Logger log = LoggerFactory.getLogger(SensitiveMaskingService.class);

    private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
    private static final Pattern ID_CARD_PATTERN = Pattern.compile("^\\d{15}$|^\\d{17}[\\dXx]$");
    private static final Pattern BANK_CARD_PATTERN = Pattern.compile("^\\d{16,19}$");
    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");

    // 配置化脱敏规则缓存
    private final Map<String, String> maskingRules = new ConcurrentHashMap<>();

    private final PermissionCheckService permissionCheckService;
    private final SystemConfigRepository systemConfigRepository;

    public SensitiveMaskingService(PermissionCheckService permissionCheckService,
                                  SystemConfigRepository systemConfigRepository) {
        this.permissionCheckService = permissionCheckService;
        this.systemConfigRepository = systemConfigRepository;
    }

    /**
     * 初始化时加载脱敏规则配置
     */
    @PostConstruct
    public void initMaskingRules() {
        loadMaskingRules();
    }

    /**
     * 从数据库加载脱敏规则配置
     */
    public void loadMaskingRules() {
        try {
            // 加载各类敏感字段的脱敏规则配置
            String[] fieldTypes = {"phone", "idcard", "bankcard", "email"};
            for (String fieldType : fieldTypes) {
                String configKey = "sensitive.mask." + fieldType;
                systemConfigRepository.findByConfigKey(configKey).ifPresent(config -> {
                    maskingRules.put(fieldType, config.getConfigValue());
                    log.info("已加载脱敏规则配置: {} = {}", fieldType, config.getConfigValue());
                });
            }
            // 如果没有配置，使用默认规则
            if (!maskingRules.containsKey("phone")) {
                maskingRules.put("phone", "3-4"); // 默认: 138****5678
            }
            if (!maskingRules.containsKey("idcard")) {
                maskingRules.put("idcard", "6-4"); // 默认: 310110********1234
            }
            if (!maskingRules.containsKey("bankcard")) {
                maskingRules.put("bankcard", "4-4"); // 默认: 6222 **** **** 1234
            }
            if (!maskingRules.containsKey("email")) {
                maskingRules.put("email", "default"); // 默认: t**t@example.com
            }
            log.info("脱敏规则配置初始化完成: {}", maskingRules);
        } catch (Exception e) {
            log.warn("加载脱敏规则配置失败，使用默认规则: {}", e.getMessage());
            // 使用默认规则
            maskingRules.put("phone", "3-4");
            maskingRules.put("idcard", "6-4");
            maskingRules.put("bankcard", "4-4");
            maskingRules.put("email", "default");
        }
    }

    /**
     * 刷新脱敏规则配置（供配置变更时调用）
     */
    public void refreshMaskingRules() {
        loadMaskingRules();
        log.info("脱敏规则配置已刷新");
    }

    /**
     * 判断用户是否有权查看敏感数据明文
     */
    public boolean canViewSensitiveData(Long userId) {
        return permissionCheckService.hasPermission(userId, "system.sensitive.access.ALL");
    }

    /**
     * 对手机号进行脱敏
     * 脱敏规则由配置驱动: sensitive.mask.phone
     */
    public String maskPhone(String phone) {
        if (phone == null || phone.isBlank()) {
            return "";
        }
        // 移除所有非数字字符
        String digits = phone.replaceAll("\\D", "");
        if (!PHONE_PATTERN.matcher(digits).matches()) {
            return phone; // 不是有效手机号，不脱敏
        }
        // 使用配置化的脱敏规则，不带空格
        String rule = maskingRules.getOrDefault("phone", "3-4");
        return applyMaskingRuleSimple(digits, rule);
    }

    /**
     * 对手机号进行脱敏（带规则参数）
     * @param phone 手机号
     * @param rule 脱敏规则
     */
    public String maskPhone(String phone, String rule) {
        if (phone == null || phone.isBlank()) {
            return "";
        }
        // 移除所有非数字字符
        String digits = phone.replaceAll("\\D", "");
        if (!PHONE_PATTERN.matcher(digits).matches()) {
            return phone; // 不是有效手机号，不脱敏
        }
        // 使用配置化的脱敏规则，不带空格
        String effectiveRule = rule != null && !rule.isEmpty() ? rule : maskingRules.getOrDefault("phone", "3-4");
        return applyMaskingRuleSimple(digits, effectiveRule);
    }

    /**
     * 对身份证号进行脱敏
     * 脱敏规则由配置驱动: sensitive.mask.idcard
     */
    public String maskIdCard(String idCard) {
        if (idCard == null || idCard.isBlank()) {
            return "";
        }
        String digits = idCard.replaceAll("\\D", "");
        if (!ID_CARD_PATTERN.matcher(digits).matches()) {
            return idCard; // 不是有效身份证号，不脱敏
        }

        // 检查是否有自定义配置
        String rule = maskingRules.get("idcard");
        if (rule != null && !rule.isEmpty()) {
            // 使用配置化的脱敏规则
            if (digits.length() == 15) {
                return applyMaskingRuleSimple(digits, rule);
            } else if (digits.length() == 18) {
                return applyMaskingRuleSimple(digits, rule);
            }
        }

        // 默认规则：兼容旧逻辑
        if (digits.length() == 15) {
            // 15位: 6位前缀 + 5位掩码 + 4位后缀
            return digits.substring(0, 6) + "*****" + digits.substring(digits.length() - 4);
        } else if (digits.length() == 18) {
            return digits.substring(0, 6) + "********" + digits.substring(digits.length() - 4);
        }
        return idCard;
    }

    /**
     * 对银行卡号进行脱敏
     * 脱敏规则由配置驱动: sensitive.mask.bankcard
     */
    public String maskBankCard(String bankCard) {
        if (bankCard == null || bankCard.isBlank()) {
            return "";
        }
        String digits = bankCard.replaceAll("\\D", "");
        if (!BANK_CARD_PATTERN.matcher(digits).matches()) {
            return bankCard; // 不是有效银行卡号，不脱敏
        }

        // 检查是否有自定义配置
        String rule = maskingRules.get("bankcard");
        if (rule != null && !rule.isEmpty()) {
            // 使用配置化的脱敏规则，带空格
            return applyMaskingRuleWithSpace(digits, rule);
        }

        // 默认规则：兼容旧逻辑，不带空格
        int len = digits.length();
        if (len == 16) {
            return digits.substring(0, 4) + "********" + digits.substring(12);
        } else if (len == 19) {
            // 19位: 4位前缀 + 11位掩码 + 4位后缀
            int maskLen = len - 8;
            StringBuilder mask = new StringBuilder();
            for (int i = 0; i < maskLen; i++) {
                mask.append("*");
            }
            return digits.substring(0, 4) + mask + digits.substring(len - 4);
        }
        return bankCard;
    }

    /**
     * 对邮箱进行脱敏
     * 脱敏规则由配置驱动: sensitive.mask.email
     */
    public String maskEmail(String email) {
        if (email == null || email.isBlank()) {
            return "";
        }
        if (!EMAIL_PATTERN.matcher(email).matches()) {
            return email; // 不是有效邮箱，不脱敏
        }

        // 检查是否有自定义配置
        String rule = maskingRules.get("email");
        if (rule != null && !rule.isEmpty() && !"default".equals(rule)) {
            // 使用配置化的脱敏规则
            return applyEmailMaskingRule(email, rule);
        }

        // 默认规则：首字母+末字母脱敏
        return applyEmailMaskingRule(email, "default");
    }

    /**
     * 对邮箱进行脱敏（带规则参数）
     * @param email 邮箱地址
     * @param rule 脱敏规则
     */
    public String maskEmail(String email, String rule) {
        if (email == null || email.isBlank()) {
            return "";
        }
        if (!EMAIL_PATTERN.matcher(email).matches()) {
            return email; // 不是有效邮箱，不脱敏
        }

        // 检查是否有自定义配置
        String configRule = maskingRules.get("email");
        String effectiveRule = rule != null && !rule.isEmpty() ? rule : configRule;
        if (effectiveRule != null && !effectiveRule.isEmpty() && !"default".equals(effectiveRule)) {
            // 使用配置化的脱敏规则
            return applyEmailMaskingRule(email, effectiveRule);
        }

        // 默认规则：首字母+末字母脱敏
        return applyEmailMaskingRule(email, "default");
    }

    /**
     * 应用脱敏规则（简单版，不带空格格式化）
     * @param value 原始值
     * @param rule 脱敏规则，格式如 "3-4" 表示保留前3位和后4位
     * @return 脱敏后的值
     */
    private String applyMaskingRuleSimple(String value, String rule) {
        if (value == null || rule == null || rule.equals("default")) {
            return value;
        }
        try {
            String[] parts = rule.split("-");
            if (parts.length == 2) {
                int prefixLen = Integer.parseInt(parts[0]);
                int suffixLen = Integer.parseInt(parts[1]);
                if (value.length() > prefixLen + suffixLen) {
                    String prefix = value.substring(0, prefixLen);
                    String suffix = value.substring(value.length() - suffixLen);
                    int maskLen = value.length() - prefixLen - suffixLen;
                    StringBuilder mask = new StringBuilder();
                    for (int i = 0; i < maskLen; i++) {
                        mask.append("*");
                    }
                    return prefix + mask + suffix;
                }
            }
        } catch (NumberFormatException e) {
            log.warn("无效的脱敏规则: {}，使用默认值", rule);
        }
        return value;
    }

    /**
     * 应用脱敏规则（带空格格式化）
     * @param value 原始值
     * @param rule 脱敏规则，格式如 "3-4" 表示保留前3位和后4位
     * @return 脱敏后的值
     */
    private String applyMaskingRule(String value, String rule) {
        if (value == null || rule == null || rule.equals("default")) {
            return value;
        }
        try {
            String[] parts = rule.split("-");
            if (parts.length == 2) {
                int prefixLen = Integer.parseInt(parts[0]);
                int suffixLen = Integer.parseInt(parts[1]);
                if (value.length() > prefixLen + suffixLen) {
                    String prefix = value.substring(0, prefixLen);
                    String suffix = value.substring(value.length() - suffixLen);
                    // 根据原始值长度决定中间脱敏字符
                    int maskLen = value.length() - prefixLen - suffixLen;
                    StringBuilder mask = new StringBuilder();
                    for (int i = 0; i < maskLen; i++) {
                        mask.append("*");
                    }
                    // 格式化输出，每4位一组
                    return formatWithSpaces(prefix + mask + suffix);
                }
            }
        } catch (NumberFormatException e) {
            log.warn("无效的脱敏规则: {}，使用默认值", rule);
        }
        return value;
    }

    /**
     * 格式化字符串，添加空格分隔
     */
    private String formatWithSpaces(String value) {
        if (value == null || value.length() <= 4) {
            return value;
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < value.length(); i++) {
            if (i > 0 && i % 4 == 0) {
                sb.append(" ");
            }
            sb.append(value.charAt(i));
        }
        return sb.toString();
    }

    /**
     * 应用带空格的脱敏规则（用于银行卡号）
     */
    private String applyMaskingRuleWithSpace(String value, String rule) {
        if (value == null || rule == null || rule.equals("default")) {
            return value;
        }
        try {
            String[] parts = rule.split("-");
            if (parts.length == 2) {
                int prefixLen = Integer.parseInt(parts[0]);
                int suffixLen = Integer.parseInt(parts[1]);
                if (value.length() > prefixLen + suffixLen) {
                    String prefix = value.substring(0, prefixLen);
                    String suffix = value.substring(value.length() - suffixLen);
                    int maskLen = value.length() - prefixLen - suffixLen;
                    StringBuilder mask = new StringBuilder();
                    for (int i = 0; i < maskLen; i++) {
                        mask.append("*");
                    }
                    return formatWithSpaces(prefix + mask + suffix);
                }
            }
        } catch (NumberFormatException e) {
            log.warn("无效的脱敏规则: {}，使用默认值", rule);
        }
        return value;
    }

    /**
     * 应用邮箱脱敏规则
     * 默认规则: 只保留第一个字符和@后域名，如 a**@example.com
     */
    private String applyEmailMaskingRule(String email, String rule) {
        if (email == null) {
            return email;
        }

        int atIndex = email.indexOf('@');
        if (atIndex <= 0) {
            return email;
        }
        String localPart = email.substring(0, atIndex);
        String domainPart = email.substring(atIndex);

        // 如果rule为null或"default"，使用默认脱敏规则
        if (rule == null || rule.equals("default")) {
            // 默认规则：只保留第一个字符
            if (localPart.length() <= 1) {
                return "***" + domainPart;
            }
            return localPart.charAt(0) + "***" + domainPart;
        }

        // 解析规则，格式如 "2-1" 表示保留前2位和后1位
        try {
            String[] parts = rule.split("-");
            if (parts.length == 2) {
                int prefixLen = Math.min(Integer.parseInt(parts[0]), localPart.length());
                int suffixLen = Math.min(Integer.parseInt(parts[1]), localPart.length() - prefixLen);
                if (localPart.length() > prefixLen + suffixLen) {
                    String prefix = localPart.substring(0, prefixLen);
                    String suffix = localPart.substring(localPart.length() - suffixLen);
                    return prefix + "**" + suffix + domainPart;
                }
            }
        } catch (NumberFormatException e) {
            log.warn("无效的邮箱脱敏规则: {}，使用默认值", rule);
        }

        // 默认规则
        if (localPart.length() <= 2) {
            return localPart.charAt(0) + "**" + domainPart;
        }
        return localPart.charAt(0) + "**" + localPart.charAt(localPart.length() - 1) + domainPart;
    }

    /**
     * 根据用户权限决定是否脱敏
     * @param value 原始值
     * @param type 数据类型：phone, idCard, bankCard, email
     * @param userId 当前用户ID
     * @return 如果用户有权限返回原值，否则返回脱敏后的值
     */
    public String mask(String value, String type, Long userId) {
        if (value == null || value.isBlank()) {
            return "";
        }
        // 如果用户有查看敏感数据权限，返回原值
        if (canViewSensitiveData(userId)) {
            return value;
        }
        // 根据类型进行脱敏
        String typeLower = type.toLowerCase();
        if (typeLower.equals("phone")) {
            return maskPhone(value);
        } else if (typeLower.equals("idcard") || typeLower.equals("id_card")) {
            return maskIdCard(value);
        } else if (typeLower.equals("bankcard") || typeLower.equals("bank_card")) {
            return maskBankCard(value);
        } else if (typeLower.equals("email")) {
            return maskEmail(value);
        }
        return value;
    }

    /**
     * 批量脱敏Map中的敏感字段
     * @param data 数据Map
     * @param fields 需要脱敏的字段名和类型的映射
     * @param userId 当前用户ID
     */
    public void maskFields(java.util.Map<String, Object> data, java.util.Map<String, String> fields, Long userId) {
        if (data == null || fields == null) {
            return;
        }
        // 如果用户有查看敏感数据权限，不进行脱敏
        if (canViewSensitiveData(userId)) {
            return;
        }
        for (var entry : fields.entrySet()) {
            String fieldName = entry.getKey();
            String fieldType = entry.getValue();
            Object value = data.get(fieldName);
            if (value != null) {
                data.put(fieldName, mask(value.toString(), fieldType, userId));
            }
        }
    }
}
