package ink.wgink.database.service.jdbc.impl;

import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.database.enums.ConnectionTypeEnum;
import ink.wgink.database.manager.ActiveConnectionManager;
import ink.wgink.database.pojo.pos.mysql.MysqlPO;
import ink.wgink.database.pojo.vos.sql.SqlVO;
import ink.wgink.database.service.connection.IConnection;
import ink.wgink.database.service.connection.impl.MySqlConnectionImpl;
import ink.wgink.database.service.jdbc.IJdbcService;
import ink.wgink.database.service.mysql.IMysqlService;
import ink.wgink.exceptions.SearchException;
import ink.wgink.exceptions.base.SystemException;
import ink.wgink.pojo.result.SuccessResultList;
import ink.wgink.util.jdbc.JdbcUtil;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * @ClassName: JdbcServiceImpl
 * @Description: jdbc
 * @Author: wanggeng
 * @Date: 2021/10/27 9:59 上午
 * @Version: 1.0
 */
@Service
public class JdbcServiceImpl extends DefaultBaseService implements IJdbcService {

    @Autowired
    private IMysqlService mysqlService;

    @Override
    public Boolean isConnected(String mysqlId) {
        Connection connection = ActiveConnectionManager.getInstance().getConnection(ConnectionTypeEnum.MYSQL, mysqlId);
        if (connection == null) {
            return false;
        }
        return true;
    }

    @Override
    public void openConnection(String mysqlId) throws SQLException {
        Connection connection = ActiveConnectionManager.getInstance().getConnection(ConnectionTypeEnum.MYSQL, mysqlId);
        if (connection != null && !connection.isClosed()) {
            return;
        }
        MysqlPO mysqlPO = mysqlService.getPO(mysqlId);
        if (mysqlPO == null) {
            throw new SearchException("数据库配置不存在");
        }
        IConnection conn = new MySqlConnectionImpl(mysqlPO.getMysqlHost(), mysqlPO.getMysqlPort(), mysqlPO.getMysqlUsername(), mysqlPO.getMysqlPassword());
        ActiveConnectionManager.getInstance().add(ConnectionTypeEnum.MYSQL, mysqlId, conn.connect());
    }

    @Override
    public void closeConnection(String mysqlId) throws SQLException {
        ActiveConnectionManager.getInstance().closeConnection(ConnectionTypeEnum.MYSQL, mysqlId);
    }

    @Override
    public List<Map<String, Object>> listSchemata(String mysqlId) throws SQLException {
        Connection connection = getConnection(mysqlId);
        String SQL = "SELECT * FROM `information_schema`.`SCHEMATA`";
        PreparedStatement preparedStatement = connection.prepareStatement(SQL);
        return JdbcUtil.listResult(preparedStatement.executeQuery());
    }

    @Override
    public List<Map<String, Object>> listTable(String mysqlId, String schemata) throws SQLException {
        Connection connection = getConnection(mysqlId);
        String SQL = "SELECT * FROM `information_schema`.`TABLES` WHERE TABLE_SCHEMA = ?";
        PreparedStatement preparedStatement = connection.prepareStatement(SQL);
        preparedStatement.setString(1, schemata);
        return JdbcUtil.listResult(preparedStatement.executeQuery());
    }

    @Override
    public List<Map<String, Object>> listField(String mysqlId, String schemata, String table) throws SQLException {
        Connection connection = getConnection(mysqlId);
        String SQL = "SELECT * FROM `information_schema`.`COLUMNS` WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?";
        PreparedStatement preparedStatement = connection.prepareStatement(SQL);
        preparedStatement.setString(1, schemata);
        preparedStatement.setString(2, table);
        return JdbcUtil.listResult(preparedStatement.executeQuery());
    }

    @Override
    public List<Map<String, Object>> listData(String mysqlId, String schemata, String table) throws SQLException {
        Connection connection = getConnection(mysqlId);
        String SQL = String.format("SELECT * FROM `%s`.`%s`", schemata, table);
        PreparedStatement preparedStatement = connection.prepareStatement(SQL);
        return JdbcUtil.listResult(preparedStatement.executeQuery());
    }

    @Override
    public List<Map<String, Object>> listData(String mysqlId, String schemata, String table, SqlVO sqlVO) throws SQLException {
        String sql = Base64.encodeBase64String(sqlVO.getSql().getBytes(StandardCharsets.UTF_8));
        Connection connection = getConnection(mysqlId);
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        return JdbcUtil.listResult(preparedStatement.executeQuery());
    }

    @Override
    public SuccessResultList<List<Map<String, Object>>> listPageData(String mysqlId, String schemata, String table, int page, int size) throws SQLException {
        if (page < 1) {
            page = 1;
        }
        if (size <= 0) {
            size = 20;
        }
        String SQL = String.format("SELECT * FROM `%s`.`%s`", schemata, table);
        return listPageQuery(mysqlId, SQL, page, size);
    }

    @Override
    public SuccessResultList<List<Map<String, Object>>> listPageQuerySql(String mysqlId, int page, int size, SqlVO sqlVO) throws SQLException {
        if (page < 1) {
            page = 1;
        }
        if (size <= 0) {
            size = 20;
        }
        return listPageQuery(mysqlId, sqlVO.getSql(), page, size);
    }

    @Override
    public void updateSql(String mysqlId, SqlVO sqlVO) throws SQLException {
        Connection connection = getConnection(mysqlId);
        PreparedStatement preparedStatement = connection.prepareStatement(sqlVO.getSql());
        preparedStatement.executeUpdate();
    }

    /**
     * 执行请求
     *
     * @param mysqlId
     * @param sql
     * @param page
     * @param size
     * @return
     * @throws SQLException
     */
    private SuccessResultList<List<Map<String, Object>>> listPageQuery(String mysqlId, String sql, int page, int size) throws SQLException {
        // 总数
        Connection connection = getConnection(mysqlId);
        String countSQL = String.format("SELECT COUNT(*) total FROM (%s) t", sql);
        PreparedStatement preparedStatement = connection.prepareStatement(countSQL);
        Map<String, Object> countResult = JdbcUtil.getResult(preparedStatement.executeQuery());
        // 列表
        String querySQL = String.format("%s LIMIT ?,?", sql);
        preparedStatement = connection.prepareStatement(querySQL);
        preparedStatement.setInt(1, (page - 1) * size);
        preparedStatement.setInt(2, size);
        List<Map<String, Object>> queryResult = JdbcUtil.listResult(preparedStatement.executeQuery());

        return new SuccessResultList<>(queryResult, page, Long.valueOf(countResult.get("total").toString()));
    }

    /**
     * 得到连接
     *
     * @return
     */
    private Connection getConnection(String mysqlId) throws SQLException {
        Connection connection = ActiveConnectionManager.getInstance().getConnection(ConnectionTypeEnum.MYSQL, mysqlId);
        if (connection == null || connection.isClosed()) {
            throw new SystemException("请重新连接数据库");
        }
        return connection;
    }

}
