package com.tzy.common.utils.bean;

import com.github.pagehelper.PageInfo;
import com.tzy.common.annotation.Sensitive;
import com.tzy.common.annotation.View;
import com.tzy.common.exception.ServiceException;
import com.tzy.common.utils.UserUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 敏感数据处理工具类
 */
@Slf4j
public class SensitiveDataUtils {

    private static final String TARGET_PACKAGE_PREFIX_1 = "java";
    private static final String TARGET_PACKAGE_PREFIX_2 = "jakarta";

    public static void handleSensitiveData(Object obj) {
        Set<Object> visited = Collections.newSetFromMap(new IdentityHashMap<>());
        try {
            handleSensitiveData(obj, visited);
        } catch (Exception e) {
            log.error("数据脱敏处理异常", e);
            throw new ServiceException("数据处理异常");
        }
    }

    private static void handleSensitiveData(Object obj, Set<Object> visited) throws IllegalAccessException {
        if (obj == null || visited.contains(obj)) {
            return;
        }

        visited.add(obj);

        if (obj instanceof Collection) {
            for (Object item : (Collection<?>) obj) {
                handleSensitiveData(item, visited);
            }
        } else if (obj instanceof Map) {
            for (Map.Entry<?, ?> entry : ((Map<?, ?>) obj).entrySet()) {
                handleSensitiveData(entry.getValue(), visited);
            }
        } else if (obj instanceof PageInfo) {
            handlePageInfo((PageInfo<?>) obj, visited);
        } else if (obj.getClass().isArray()) {
            int length = java.lang.reflect.Array.getLength(obj);
            for (int i = 0; i < length; i++) {
                handleSensitiveData(java.lang.reflect.Array.get(obj, i), visited);
            }
        } else if (shouldProcess(obj)) {
            handleFields(obj, visited);
        }
    }

    private static void handlePageInfo(PageInfo<?> pageInfo, Set<Object> visited) throws IllegalAccessException {
        if (pageInfo == null) {
            return;
        }
        // 处理PageInfo中的列表数据
        handleSensitiveData(pageInfo.getList(), visited);
    }

    private static void handleFields(Object obj, Set<Object> visited) throws IllegalAccessException {
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                Object value = field.get(obj);
                if (field.isAnnotationPresent(Sensitive.class) && value instanceof String) {
                    Sensitive annotation = field.getAnnotation(Sensitive.class);
                    field.set(obj, maskString((String) value,annotation.type()));
                } else if (field.isAnnotationPresent(View.class)){
                    View annotation = field.getAnnotation(View.class);
                    field.set(obj, view(value, annotation.type()));
                }else {
                    handleSensitiveData(value, visited);
                }
            } catch (Exception e) {
                log.error("数据脱敏处理异常 field: " + field.getName(), e);
                throw e;
            }
        }
    }

    private static boolean shouldProcess(Object obj) {
        Package objPackage = obj.getClass().getPackage();
        if (objPackage != null &&
                (objPackage.getName().startsWith(TARGET_PACKAGE_PREFIX_1) || objPackage.getName().startsWith(TARGET_PACKAGE_PREFIX_2))) {
            // Ignore Java
            return false;
        }
        return true;
    }

    private static String maskString(String str, int type) {
        if (type == 1) {
            return UserUtils.hideUserPhone(str);
        }
        if (type == 2) {
            return null;
        }
        if (type == 3) {
            String newStr = UserUtils.hideUserPhone(str);
            if (Objects.equals(newStr, str) && newStr.length() > 3) {
                String prefix = newStr.substring(0, 2);
                String suffix = newStr.substring(newStr.length() - 2);
                return prefix + "***" + suffix;
            }
            return newStr;
        }
        if (StringUtils.isEmpty(str)) {
            return str;
        }
        return str.charAt(0) + "**";
    }

    private static Object view(Object value, int type) {
        if (Objects.isNull(value))
            return value;
        if (type == 1)
            return null;
        return value;
    }
}
