package org.xyzh.common.jdbc.handler;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @description    通用枚举类型处理器，支持枚举类中定义 getName() 方法
 *                 将枚举的 name 属性（自定义字符串）存储到数据库
 * @filename    EnumNameTypeHandler.java
 * @author    yslg
 * @copyright xyzh
 * @since 2025-12-18
 */
public class EnumNameTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {

    private final Class<E> type;

    public EnumNameTypeHandler(Class<E> type) {
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        }
        this.type = type;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
        String value = getEnumName(parameter);
        ps.setString(i, value);
    }

    @Override
    public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String name = rs.getString(columnName);
        return fromName(name);
    }

    @Override
    public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String name = rs.getString(columnIndex);
        return fromName(name);
    }

    @Override
    public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String name = cs.getString(columnIndex);
        return fromName(name);
    }

    /**
     * 获取枚举的 name 属性值
     * 优先调用 getName() 方法，如果不存在则使用 name()
     */
    private String getEnumName(E enumValue) {
        try {
            java.lang.reflect.Method getNameMethod = type.getMethod("getName");
            return (String) getNameMethod.invoke(enumValue);
        } catch (NoSuchMethodException e) {
            return enumValue.name();
        } catch (Exception e) {
            return enumValue.name();
        }
    }

    /**
     * 根据 name 属性值查找枚举
     * 优先匹配 getName()，如果不存在则匹配 name()
     */
    private E fromName(String name) {
        if (name == null) {
            return null;
        }
        E[] enumConstants = type.getEnumConstants();
        
        // 先尝试匹配 getName()
        try {
            java.lang.reflect.Method getNameMethod = type.getMethod("getName");
            for (E enumConstant : enumConstants) {
                String enumName = (String) getNameMethod.invoke(enumConstant);
                if (name.equals(enumName)) {
                    return enumConstant;
                }
            }
        } catch (NoSuchMethodException e) {
            // 没有 getName 方法，使用 name()
        } catch (Exception e) {
            // 其他异常，使用 name()
        }
        
        // 回退到 name() 匹配
        for (E enumConstant : enumConstants) {
            if (name.equals(enumConstant.name())) {
                return enumConstant;
            }
        }
        
        return null;
    }
}
