package com.jeequan.jeepay.db.typehandler;

import com.jeequan.jeepay.service.impl.SysConfigService;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

/**
 * 敏感数据， 自动加解密
 * 注意： 使用LambdaUpdateWrapper不支持自定义BaseTypeHandler (https://github.com/baomidou/mybatis-plus/issues/3317)
 * 支持： 分页查询、 条件查询、 ID查询、 ID更新、 record+ query条件更新、 不支持LambdaUpdateWrapper ！ 切记
 * <p>
 * 使用方式：
 * 1. Model中       @TableName(value = "t_xxxx", autoResultMap = true)
 * 字段： @TableField(typeHandler = EncryptTypeHandler.class)
 * 2. mapper.xml   字段： 加入： typeHandler="com.jeequan.jeepay.db.typehandler.EncryptTypeHandler"  属性。
 *
 * @author terrfly
 * @date 2022/5/16 9:13
 */
public class EncryptTypeHandler<T> extends BaseTypeHandler<T> {

    private static final Logger log = LoggerFactory.getLogger(EncryptTypeHandler.class);

    /**
     * 执行之前，将Java类型转换为对应的jdbc类型，用于赋值sql中参数
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {

        // 加密存储 base64格式 空串也加密
        ps.setString(i, (parameter == null ? null : SysConfigService.DB_ENCRYPT_SM4.encryptBase64(parameter.toString())));
    }

    /**
     * 根据列名从resultSet中获取，将JDBC类型转换为Java类型
     */
    @Override
    public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return commonGetVal(rs.getString(columnName));
    }

    /**
     * 据下标从resultSet中获取，将JDBC类型转换为Java类型
     */
    @Override
    public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return commonGetVal(rs.getString(columnIndex));
    }

    /**
     * 用于在执行完存储过程后，将JDBC类型转换为Java类型
     */
    @Override
    public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return commonGetVal(cs.getString(columnIndex));
    }


    /**
     * 通用获取值的函数
     **/
    private T commonGetVal(String val) {
        if (val == null) {
            return null;
        }

        try {
            return (T) SysConfigService.DB_ENCRYPT_SM4.decryptStr(val);
        } catch (Exception e) {
            log.info("数据解密异常, {}", val);

            return (T) val;
        }
    }
}
