package com.system.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.system.dto.DockerServiceDto;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Component;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author ly
 */
//@MappedTypes({JSONArray.class}) // 因为BaseTypeHandler<JSONArray> 泛型中指定了JSONArray 的话，这个注解也可以省略
@MappedJdbcTypes(value = JdbcType.LONGVARCHAR, includeNullJdbcType = true)
@Component
public class DockerServiceDtoTypeHandler extends BaseTypeHandler<List<DockerServiceDto>> implements InitializingBean {
    static DockerServiceDtoTypeHandler j;
    @Autowired
    ObjectMapper objectMapper;

    /**
     * 魔法 注入 单例bean objectMapper;
     * 在 @Controller 中注入ObjectMapper 不需要这么麻烦，直接 @Autowired 即可 。
     * 非Controller 注入原理：spring 启动过程中 实例化JsonNodeTypeHandler 的 bean 时，会自动把 objectMapper 携带过来；
     * spring 启动完成后的bean 又会被擦除 。所以，这个要及时赋值一下引用 objectMapper
     */
    @Override
    public void afterPropertiesSet() {
        j = this; // 初始化静态实例
        j.objectMapper = this.objectMapper; //及时拷贝引用
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, List<DockerServiceDto> jsonNode, JdbcType jdbcType) throws SQLException {
        ps.setString(i, jsonNode != null ? JSON.toJSONString(jsonNode, SerializerFeature.WriteMapNullValue) : "[]");
    }

    @SneakyThrows
    @Override
    public List<DockerServiceDto> getNullableResult(ResultSet rs, String colName) {
        return read(rs.getString(colName));
    }

    @SneakyThrows
    @Override
    public List<DockerServiceDto> getNullableResult(ResultSet rs, int colIndex) {
        return read(rs.getString(colIndex));
    }

    @SneakyThrows
    @Override
    public List<DockerServiceDto> getNullableResult(CallableStatement cs, int i) {
        return read(cs.getString(i));
    }

    @SneakyThrows
    private List<DockerServiceDto> read(String json) {
        return !StringUtils.isEmpty(json) ? Arrays.asList(j.objectMapper.readValue(json, DockerServiceDto[].class)) : new ArrayList<>();
    }
}
