/*
 * Copyright (c) 2018-2028, AoKunSang All rights reserved.
 * 我问青山何时老，青山问我几时闲，
 * 不是闲人闲不得，能闲必非等闲人。
 */
package org.springblade.core.mp.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.ClassUtils;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.Reflector;
import org.apache.ibatis.reflection.invoker.Invoker;
import org.apache.ibatis.type.SimpleTypeRegistry;
import org.springblade.core.mp.annotation.TableBizId;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 获取业务ID工具类
 *
 * @author wookvn
 * @datetime 2024-12-24 14:59:26
 */
@Slf4j
public class TableBizIdUtil {

    private static final Map<Class<?>, BizIdInfo> TABLE_INFO_CACHE = new ConcurrentHashMap();

    /**
     * <p>获取某个类的业务ID字段名</p>
     * @author wookvn
     * @datetime 2024-12-24 15:01:07
     * @param clazz: 类class
     * @return java.lang.String
     **/
    public static BizIdInfo getTableBizIdInfo(Class<?> clazz) {
        if (clazz != null && !clazz.isPrimitive() && !SimpleTypeRegistry.isSimpleType(clazz) && !clazz.isInterface()) {
            Class<?> targetClass = ClassUtils.getUserClass(clazz);
            //从缓存取业务ID
            BizIdInfo bizIdInfo = TABLE_INFO_CACHE.get(targetClass);

            if (bizIdInfo == null) {
                //从Class获取
                Field bizIdField = getTableBizIdField(clazz);
                //优先从注解中获取字段名
                String bizIdColumnName = bizIdField.getAnnotation(TableBizId.class).value();
                //注解中没有设置字段名，从字段属性名驼峰命名转换到表字段名
                if(StrUtil.isBlank(bizIdColumnName)) {
                    bizIdColumnName = StringUtils.camelToUnderline(bizIdField.getName());
                }
                Reflector reflector = new Reflector(clazz);
                Invoker getInvoker = reflector.getGetInvoker(bizIdField.getName());
                if(getInvoker == null) {
                    throw new RuntimeException(String.format("Entity类[%s]|未找到属性名为{%s}的getter方法", clazz.getName(), bizIdField.getName()));
                }
                bizIdInfo = new BizIdInfo(bizIdColumnName, getInvoker);
                //放入缓存
                TABLE_INFO_CACHE.put(clazz, bizIdInfo);
            }
            return bizIdInfo;
        }else {
            return null;
        }
    }

    /**
     * <p>获取类的业务ID字段名</p>
     * @author wookvn
     * @datetime 2024-12-24 15:11:27
     * @param clazz: 类class
     * @return java.lang.reflect.Field
     **/
    private static Field getTableBizIdField(Class<?> clazz) {
        List<Field> fieldList = ReflectionKit.getFieldList(ClassUtils.getUserClass(clazz));
        List<Field> fields = fieldList.stream().filter((field) -> {
            TableBizId tableBizId = field.getAnnotation(TableBizId.class);
            return tableBizId != null;
        }).collect(Collectors.toList());
        if(CollectionUtil.isEmpty(fields)) {
            throw new IllegalArgumentException(String.format("Entity类[%s]|没有查找到@TableBizId注解。", clazz.getName()));
        }
        if(fields.size() > 1) {
            throw new IllegalArgumentException(String.format("Entity类[%s]|@TableBizId注解有且只能存在一个。", clazz.getName()));
        }
        return fields.get(0);
    }
}
