package com.keyware.shandan.dynacmicform.core.db.executor;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.keyware.shandan.common.util.StringUtils;
import com.keyware.shandan.dynacmicform.config.spring.ContextHelper;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.Reader;
import java.sql.Date;
import java.sql.*;
import java.util.*;

@Component
public class SqlExecutor {
    private static final Logger log = LoggerFactory.getLogger(SqlExecutor.class);

    private final SqlSession sqlSession;

    public SqlExecutor(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
    }

    /**
     * 检查SQL是否可以正常执行
     *
     * @param sql sql
     * @return boolean
     */
    public boolean validateQuery(String sql) {
        try (Connection conn = getConnection(); PreparedStatement stmt = conn.prepareStatement(sql)) {
            ResultSet rs = stmt.executeQuery();
            rs.close();
            log.debug("==> {}", sql);
            return true;
        } catch (Exception e) {
            log.trace("执行验证SQL:{} 失败:{}", sql, e.getMessage());
            return false;
        }
    }

    public boolean execute(String sql) throws Exception {
        if (StringUtils.isEmpty(sql)) {
            return false;
        }
        log.debug("==>  SQL: " + sql);

        try {
            Connection conn = sqlSession.getConnection();
            PreparedStatement stmt = conn.prepareStatement(sql);
            return stmt.execute();
        } catch (Exception e) {
            log.error("执行sql查询异常: " + sql, e);
            throw e;
        }
    }

    /**
     * 批量执行sql语句
     *
     * @param sqlList
     * @return
     * @throws SQLException
     */
    public int[] executeBatch(Collection<String> sqlList) throws SQLException {
        int[] count = new int[sqlList.size()];
        if (sqlList.isEmpty()) {
            return count;
        }

        PreparedStatement stmt = null;
        try {
            Connection conn = getConnection();
            conn.setAutoCommit(false);
            for (String sql : sqlList) {
                if (StringUtils.hasText(sql)) {
                    if (stmt == null) {
                        stmt = conn.prepareStatement(sql);
                    }
                    stmt.addBatch(sql);
                }
            }
            if (stmt != null) {
                count = stmt.executeBatch();
                conn.commit();
            }
            return count;
        } catch (Exception e) {
            log.error("批量执行sql查询异常: ", e);
            throw e;
        } finally {
            if (stmt != null) {
                stmt.close();
            }
        }
    }

    /**
     * 执行更新操作
     *
     * @param sql    sql
     * @param params 参数
     * @return boolean
     * @throws Exception -
     */
    public boolean executeUpdate(String sql, Object... params) throws Exception {
        if (StringUtils.isEmpty(sql)) {
            return false;
        }

        log.debug("==>  SQL: " + sql);
        // 替换单个?参数为多个，用于拼接IN参数
        if (params != null && params.length > 0) {
            log.debug("==>  Params: {}", JSONArray.toJSONString(params));
            if (params.length > 2000) {
                log.warn("更新参数集合数量过多, size={}，请检查调用是否合理！", params.length);
            }
        }
        try {
            Connection conn = getConnection();
            PreparedStatement stmt = conn.prepareStatement(sql);
            if (params != null && params.length > 0) {
                for (int i = 0; i < params.length; i++) {
                    stmt.setObject(i + 1, params[i]);
                }
            }
            int rs = stmt.executeUpdate();
            return rs >= 0;
        } catch (Exception e) {
            log.error("执行sql查询异常: " + sql, e);
            throw e;
        }
    }


    /***
     * 执行Select语句，如: SELECT user_id,role_id FROM user_role WHERE user_id IN (?,?,?,?)
     * 查询结果如: [{"user_id":1001,"role_id":101},{"user_id":1001,"role_id":102},{"user_id":1003,"role_id":102},{"user_id":1003,"role_id":103}]
     * @param sql
     * @return
     */
    public List<Map<String, Object>> executeQuery(String sql, Object... params) throws Exception {
        if (StringUtils.isBlank(sql)) {
            return null;
        }

        log.debug("==>  SQL: " + sql);
        // 替换单个?参数为多个，用于拼接IN参数
        if (params != null && params.length > 0) {
            log.debug("==>  Params: {}", JSONArray.toJSONString(params));
            if (params.length > 2000) {
                log.warn("查询参数集合数量过多, size={}，请检查调用是否合理！", params.length);
            }
        }
        try {
            Connection conn = getConnection();
            PreparedStatement stmt = conn.prepareStatement(sql);
            if (params != null && params.length > 0) {
                for (int i = 0; i < params.length; i++) {
                    stmt.setObject(i + 1, params[i]);
                }
            }
            ResultSet rs = stmt.executeQuery();
            ResultSetMetaData meta = rs.getMetaData();
            List<Map<String, Object>> mapList = new ArrayList<>();
            if (meta.getColumnCount() > 0) {
                // 添加数据行
                while (rs.next()) {
                    Map<String, Object> dataRow = new HashMap<>();
                    for (int i = 1; i <= meta.getColumnCount(); i++) {
                        Object obj = rs.getObject(i);
                        if (obj instanceof Clob) {
                            obj = clobRsConvert(rs.getClob(i));
                        } else if (obj instanceof Date || obj instanceof Timestamp) {
                            Date date = rs.getDate(i);
                            obj = DateUtil.format(date, "yyyy-MM-dd HH:mm:ss");
                        }
                        dataRow.put(meta.getColumnLabel(i), obj);
                    }
                    mapList.add(dataRow);
                }
                rs.close();
            }
            log.debug("<==  {}", JSONArray.toJSONString(mapList));
            return mapList;
        } catch (Exception e) {
            log.error("执行Sql查询异常", e);
            throw e;
        }
    }

    private Connection getConnection() throws SQLException {
        return sqlSession.getConfiguration().getEnvironment().getDataSource().getConnection();
    }

    private static String clobRsConvert(Clob clob) {
        String clobStr = "";
        Reader inStream = null;
        try {
            inStream = clob.getCharacterStream();
            char[] c = new char[(int) clob.length()];
            if (-1 == inStream.read(c)) {
                clobStr = new String(c);
                inStream.close();
            } else {
                clobStr = clob.getSubString(1, (int) clob.length());
            }
        } catch (IOException | SQLException e) {
            log.error("转换Clob结果集时出现异常：", e);
        }
        return clobStr;
    }
}
