package com.liangjian.dataplatform.member.util;

import java.net.URLDecoder;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: 黄子奇
 * @Date: 2019/10/22
 */
public class SimpleSqlUtil {

    /**
     * 直接查询sql，返回二维字符串列表
     * @param url
     * @param username
     * @param password
     * @param sql
     * @param needDecode
     * @return
     * @throws Exception
     */
    public static List<List<String>> getDataFromDatabase(String url, String username, String password, String sql, boolean needDecode) throws Exception {
        if(needDecode) {
            sql = URLDecoder.decode(sql,"utf8");
        }
        List<List<String>> result = new ArrayList<>();

        try (Connection conn = DriverManager.getConnection(url,username,password);
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {

            while(rs.next()) {
                ResultSetMetaData rsmd1 = rs.getMetaData();
                int count = rsmd1.getColumnCount();
                List<String> cols = new ArrayList<>();

                for (int i = 1; i <= count; i++) {
                    Object col = rs.getObject(i);
                    if (col == null) {
                        cols.add("");
                    } else {
                        cols.add(col.toString());
                    }
                }
                result.add(cols);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return result;
    }

    /**
     * 通过预编译sql查询，返回二维字符串数组
     * @param url
     * @param username
     * @param password
     * @param psql
     * @param values
     * @param needDecode
     * @return
     * @throws Exception
     */
    public static List<List<String>> getDataFromDatabasePre(String url, String username, String password, String psql, List<Object> values, boolean needDecode) throws Exception {
        if(needDecode) {
            psql = URLDecoder.decode(psql,"utf8");
        }
        List<List<String>> result = new ArrayList<>();

        try (Connection conn = DriverManager.getConnection(url,username,password);
             PreparedStatement pstmt = conn.prepareStatement(psql)) {

            for (int i = 0; i < values.size(); i++) {
                Object value = values.get(i);
                pstmt.setObject(i+1, value);
            }
            ResultSet rs = pstmt.executeQuery();

            while(rs.next()) {
                ResultSetMetaData rsmd1 = rs.getMetaData();
                int count = rsmd1.getColumnCount();
                List<String> cols = new ArrayList<>();

                for (int i = 1; i <= count; i++) {
                    Object col = rs.getObject(i);
                    if (col == null) {
                        cols.add("");
                    } else {
                        cols.add(col.toString());
                    }
                }
                result.add(cols);
            }
            rs.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return result;
    }

    /**
     * 直接查询sql，返回行封装的列表
     * @param url
     * @param username
     * @param password
     * @param sql
     * @param needDecode
     * @return
     * @throws Exception
     */
    public static List<Map<String,Object>> getDataFromDatabase2(String url, String username, String password, String sql, boolean needDecode) throws Exception {
        if(needDecode) {
            sql = URLDecoder.decode(sql,"utf8");
        }
        List<Map<String,Object>> result = new ArrayList<>();

        try (Connection conn = DriverManager.getConnection(url,username,password);
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {

            boolean hasLoadNames = false;
            List<String> columnNames = new ArrayList<>();
            while (rs.next()) {
                ResultSetMetaData rsmd1 = rs.getMetaData();
                int count = rsmd1.getColumnCount();

                if (!hasLoadNames) {
                    for (int i = 1; i <= count; i++) {
                        columnNames.add(rsmd1.getColumnLabel(i));
                    }
                    hasLoadNames = true;
                }

                Map<String,Object> row = new HashMap<>();
                for (String columnName : columnNames) {
                    Object col = rs.getObject(columnName);
                    row.put(columnName,col);
                }
                result.add(row);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return result;
    }

    /**
     * 通过预编译sql查询，返回行封装的列表
     * @param url
     * @param username
     * @param password
     * @param psql
     * @param values
     * @param needDecode
     * @return
     * @throws Exception
     */
    public static List<Map<String,Object>> getDataFromDatabasePre2(String url, String username, String password, String psql, List<Object> values, boolean needDecode) throws Exception {
        if(needDecode) {
            psql = URLDecoder.decode(psql,"utf8");
        }
        List<Map<String,Object>> result = new ArrayList<>();

        try (Connection conn = DriverManager.getConnection(url,username,password);
             PreparedStatement pstmt = conn.prepareStatement(psql)) {

            for (int i = 0; i < values.size(); i++) {
                Object value = values.get(i);
                pstmt.setObject(i+1, value);
            }
            ResultSet rs = pstmt.executeQuery();

            boolean hasLoadNames = false;
            List<String> columnNames = new ArrayList<>();
            while (rs.next()) {
                ResultSetMetaData rsmd1 = rs.getMetaData();
                int count = rsmd1.getColumnCount();

                if (!hasLoadNames) {
                    for (int i = 1; i <= count; i++) {
                        columnNames.add(rsmd1.getColumnLabel(i));
                    }
                    hasLoadNames = true;
                }

                Map<String,Object> row = new HashMap<>();
                for (String columnName : columnNames) {
                    Object col = rs.getObject(columnName);
                    row.put(columnName,col);
                }
                result.add(row);
            }
            rs.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return result;
    }

    /**
     * 查询sql，封装成带分页信息的结构
     * @param url
     * @param username
     * @param password
     * @param sql
     * @param needDecode
     * @param page
     * @param size
     * @return
     * @throws Exception
     */
    public static Map<String,Object> getDataFromDatabaseWrapper(String url, String username, String password, String sql, boolean needDecode, Integer page, Integer size) throws Exception {
        if(needDecode) {
            sql = URLDecoder.decode(sql,"utf8");
        }

        String countSql = "SELECT COUNT(1) from (" + sql + ") tt";

        if (page != null && size != null) {
            Integer offset = countOffset(page,size);
            sql = String.format("%s limit %d offset %d ", sql, size, offset);
        }

        List<Map<String,Object>> items = getDataFromDatabase2(url,username,password,sql,false);
        List<List<String>> counts = getDataFromDatabase(url,username,password,countSql,false);
        String countStr = counts.get(0).get(0);
        Long count = Long.parseLong(countStr);

        Map<String,Object> result = new HashMap<>();
        result.put("items", items);
        result.put("totalCount",count);
        return result;
    }

    /**
     * 通过预编译sql查询，封装成带分页信息
     * @param url
     * @param username
     * @param password
     * @param preSql
     * @param values
     * @param needDecode
     * @param page
     * @param size
     * @return
     * @throws Exception
     */
    public static Map<String,Object> getDataFromDatabaseWrapperPre(String url, String username, String password, String preSql, List<Object> values, boolean needDecode, Integer page, Integer size) throws Exception {
        if(needDecode) {
            preSql = URLDecoder.decode(preSql,"utf8");
        }

        String countSql = "SELECT COUNT(1) from (" + preSql + ") tt";

        if (page != null && size != null) {
            Integer offset = countOffset(page,size);
            preSql = String.format("%s limit %d offset %d ", preSql, size, offset);
        }

        List<Map<String,Object>> items = getDataFromDatabasePre2(url,username,password,preSql, values,false);
        List<List<String>> counts = getDataFromDatabasePre(url,username,password,countSql,values,false);
        String countStr = counts.get(0).get(0);
        Long count = Long.parseLong(countStr);

        Map<String,Object> result = new HashMap<>();
        result.put("items", items);
        result.put("totalCount",count);
        return result;
    }

    /**
     * 查询sql，封装带总数信息
     * @param url
     * @param username
     * @param password
     * @param sql
     * @param needDecode
     * @return
     * @throws Exception
     */
    public static Map<String,Object> getDataFromDatabaseWrapperUnpagedPre(String url, String username, String password, String sql,List<Object> values, boolean needDecode) throws Exception {
        if(needDecode) {
            sql = URLDecoder.decode(sql,"utf8");
        }

        String countSql = "SELECT COUNT(1) from (" + sql + ") tt";

        List<Map<String,Object>> items = getDataFromDatabasePre2(url,username,password,sql,values,false);
        List<List<String>> counts = getDataFromDatabasePre(url,username,password,countSql,values,false);
        String countStr = counts.get(0).get(0);
        Long count = Long.parseLong(countStr);

        Map<String,Object> result = new HashMap<>();
        result.put("items", items);
        result.put("totalCount",count);
        return result;
    }

    /**
     * 计算起始偏移
     * @param page
     * @param size
     * @return
     */
    private static Integer countOffset(Integer page, Integer size) {
        if(page == 1) {
            return 0;
        }
        return (page - 1) * size + 1;
    }

    /**
     * 仅执行sql
     * @param url
     * @param username
     * @param password
     * @param psql
     * @param values
     * @param needDecode
     * @return
     * @throws Exception
     */
    public static boolean execute(String url, String username, String password, String psql, List<Object> values, boolean needDecode) throws Exception {
        if(needDecode) {
            psql = URLDecoder.decode(psql,"utf8");
        }

        try (Connection conn = DriverManager.getConnection(url,username,password);
             PreparedStatement pstmt = conn.prepareStatement(psql)){
            for (int i = 1; i <= values.size(); i++) {
                pstmt.setObject(i, values.get(i-1));
            }
            return pstmt.execute();
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }
}
