package io.hmit.modules.datasource.db;

import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleSchemaStatVisitor;
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
import com.alibaba.druid.stat.TableStat;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

/**
 * <h1>Sql解析器</h1>
 * @author Shen && syf0412@vip.qq.com
 * @since 2022/8/2 15:37
 **/
@Slf4j
public class SqlDruidParser {

    public static Map<String,Object> sqlParser(DbType dbType, String sql) {
        Map<String, Object> resultMap = new HashMap<>();
        List<SQLStatement> stmtList = null;
        try {
            String result = SQLUtils.format(sql, dbType);
            String[] sqlParam = result.split(";");
            List<String> sqlList = Arrays.asList(sqlParam);
            resultMap.put("executeSql", sqlList);
            stmtList = SQLUtils.parseStatements(sql, dbType);
        }catch(Exception e){
            log.error("SQL解析异常:{}", sql);
            resultMap.put("executeType", null);
            return resultMap;
        }
        SQLStatement stmt = stmtList.get(0);
        SchemaStatVisitor visitor = null;
        if (Objects.equals(dbType, DbType.oracle)) {
            visitor = new OracleSchemaStatVisitor();
        } else if (Objects.equals(dbType, DbType.mysql)) {
            visitor = new MySqlSchemaStatVisitor();
        }
        stmt.accept(visitor);
        Object method = getFirstOrNull(visitor.getTables());
        resultMap.put("tables", visitor.getTables());
        resultMap.put("fields", visitor.getColumns());
        resultMap.put("tableName", getTable(visitor.getTables()));
        resultMap.put("sqlContent", stmt);
        if (method != null) {
            resultMap.put("executeType", method.toString().toUpperCase());
        } else {
            resultMap.put("executeType", "SELECT");
        }
        return resultMap;
    }

    private static Object getFirstOrNull(Map<TableStat.Name, TableStat> map) {
        Object obj = null;
        for (Map.Entry<TableStat.Name, TableStat> entry : map.entrySet()) {
            obj = entry.getValue();
            if (obj != null) {
                break;
            }
        }
        return  obj;
    }

    private static Object getTable(Map<TableStat.Name, TableStat> map) {
        String tableName = null;
        for (Map.Entry<TableStat.Name, TableStat> entry : map.entrySet()) {
            TableStat.Name keys = entry.getKey();
            tableName =  keys.getName();
            if (tableName != null) {
                break;
            }
        }
        return tableName;
    }



}