package com.yeejoin.amos.boot.module.jg.biz.core;

import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yeejoin.amos.boot.biz.common.entity.BaseEntity;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Objects;

import static com.yeejoin.amos.boot.module.jg.biz.edit.utils.ReflectiveFieldAccessor.getAllFields;

public class BaseEntityService<M extends BaseMapper<T>, T extends BaseEntity> extends ServiceImpl<M, T> {


    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdateWithNull(T entity) {
        if (null != entity) {
            Class<?> cls = entity.getClass();
            TableInfo tableInfo = TableInfoHelper.getTableInfo(cls);
            Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
            String keyProperty = tableInfo.getKeyProperty();
            Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
            Object idVal = ReflectionKit.getMethodValue(cls, entity, tableInfo.getKeyProperty());
            return StringUtils.checkValNull(idVal) || Objects.isNull(getById((Serializable) idVal)) ? save(entity) : updateById(entity);
        }
        return false;
    }

    @Override
    public boolean updateById(T entity) {
        UpdateWrapper<T> wrapper = new UpdateWrapper<>();

        // 递归获取所有字段（包括父类）
        List<Field> allFields = getAllFields(entity.getClass());

        // 动态设置非空字段到 SET 语句
        allFields.stream().filter(field -> field.getAnnotation(TableField.class) != null && field.getAnnotation(TableField.class).exist()).forEach(field -> {
            String columnName = getColumnName(field); // 获取字段名（处理 @TableField 注解）
            wrapper.set(columnName, getFieldValue(field, entity));
        });
        // 设置主键条件（确保主键在父类也能获取）
        String idColumn = getColumnName(getIdField(entity.getClass())); // 获取主键字段名
        wrapper.eq(CharSequenceUtil.toUnderlineCase(idColumn).toUpperCase(), entity.getSequenceNbr());
        return super.update(null, wrapper);
    }


    // 获取主键字段（含父类）
    private Field getIdField(Class<?> clazz) {
        for (Field field : getAllFields(clazz)) {
            if (field.isAnnotationPresent(TableId.class)) { // 检查 @TableId 注解
                return field;
            }
        }
        // 默认尝试获取父类的 "id" 字段（适应 TzsBaseEntity）
        try {
            return clazz.getSuperclass().getDeclaredField("id");
        } catch (NoSuchFieldException e) {
            throw new RuntimeException("未找到主键字段", e);
        }
    }

    // 获取字段名（支持 @TableField 注解）
    private String getColumnName(Field field) {
        TableField tableField = field.getAnnotation(TableField.class);
        if (tableField != null && !tableField.value().isEmpty()) {
            return tableField.value(); // 使用注解指定的列名
        }
        return StringUtils.camelToUnderline(field.getName()); // 驼峰转下划线
    }

    // 安全获取字段值
    private Object getFieldValue(Field field, Object obj) {
        try {
            field.setAccessible(true);
            return field.get(obj);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("获取字段值失败", e);
        }
    }

}
