package com.njzscloud.common.mp.support.handler.e;

import com.njzscloud.common.core.ienum.Dict;
import com.njzscloud.common.core.ienum.DictInt;
import com.njzscloud.common.core.ienum.DictStr;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.type.EnumTypeHandler;
import org.apache.ibatis.type.JdbcType;

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

/**
 * 枚举类型处理器<br/>
 * 仅处理 Dict 类型的枚举, 其他枚举类型采用 Mybatis 默认处理器<br/>
 * 使用配置项 mybatis-plus.configuration.default-enum-type-handler
 *
 * @see Dict
 * @see DictInt
 * @see DictStr
 */
@Slf4j
public class EnumTypeHandlerDealer<E extends Enum<E>> extends EnumTypeHandler<E> {

    private final Object[] enums;
    private final EnumType enumType;

    /**
     * 构建枚举类型处理器
     *
     * @param type 枚举类型
     * @see DictInt
     * @see DictStr
     */
    public EnumTypeHandlerDealer(Class<E> type) {
        super(type);

        enums = type.getEnumConstants();

        if (DictInt.class.isAssignableFrom(type)) {
            enumType = EnumType.DICT_INT;
        } else if (DictStr.class.isAssignableFrom(type)) {
            enumType = EnumType.DICT_STR;
        } else {
            enumType = EnumType.OTHER;
            log.warn("枚举类型 [{}] 未实现 [{}] 或 [{}], 数据库操作将使用 Mybatis 默认处理器", type, DictInt.class.getName(), DictStr.class.getName());
        }
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
        switch (enumType) {
            case OTHER:
                super.setNonNullParameter(ps, i, parameter, jdbcType);
                break;
            case DICT_INT:
                ps.setObject(i, ((DictInt) parameter).getVal());
                break;
            case DICT_STR:
                ps.setObject(i, ((DictStr) parameter).getVal());
                break;
        }
    }

    @Override
    public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String strVal = rs.getString(columnName);

        if (strVal == null) {
            return null;
        }

        if (enumType == EnumType.OTHER) {
            return super.getNullableResult(rs, columnName);
        }
        return getNullableResult(strVal);
    }

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

        if (enumType == EnumType.OTHER) {
            return super.getNullableResult(rs, columnIndex);
        }
        return getNullableResult(strVal);
    }

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

        if (strVal == null) {
            return null;
        }
        if (enumType == EnumType.OTHER) {
            return super.getNullableResult(cs, columnIndex);
        }

        return getNullableResult(strVal);
    }

    @SuppressWarnings("unchecked")
    private E getNullableResult(String strVal) {
        if (enumType == EnumType.DICT_INT) {
            int val = Integer.parseInt(strVal);
            return (E) Dict.parse(val, (DictInt[]) enums);
        } else {
            return (E) Dict.parse(strVal, (DictStr[]) enums);
        }
    }

    private enum EnumType {
        OTHER,
        DICT_INT,
        DICT_STR
    }
}
