package com.njcn.gather.systemops.database.support.mysql;

import cn.hutool.core.util.StrUtil;
import com.njcn.gather.systemops.database.constant.DatabaseOpsConst;
import com.njcn.gather.systemops.database.pojo.po.DatabaseConnection;
import com.njcn.gather.systemops.database.pojo.vo.DatabaseTableVO;
import com.njcn.gather.systemops.database.pojo.vo.DatabaseTestResultVO;
import com.njcn.gather.systemops.database.support.spi.DatabaseConnectionOperator;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * MySQL 连接能力实现。
 */
@Component
public class MysqlConnectionOperator implements DatabaseConnectionOperator {

    @Override
    public boolean support(String dbType) {
        return DatabaseOpsConst.DB_TYPE_MYSQL.equalsIgnoreCase(dbType);
    }

    @Override
    public DatabaseTestResultVO test(DatabaseConnection connection, String password) {
        DatabaseTestResultVO result = new DatabaseTestResultVO();
        try (Connection ignored = openConnection(connection, password)) {
            result.setSuccess(true);
            result.setMessage("连接成功");
        } catch (Exception exception) {
            result.setSuccess(false);
            result.setMessage(exception.getMessage());
        }
        return result;
    }

    @Override
    public List<DatabaseTableVO> listTables(DatabaseConnection connection, String password, String schemaOrDatabaseName) throws Exception {
        String databaseName = StrUtil.blankToDefault(schemaOrDatabaseName, connection.getDatabaseName());
        String sql = "SELECT t.table_schema, t.table_name, t.auto_increment, t.update_time, "
                + "t.data_length, t.engine, t.table_rows, t.table_comment, "
                + "MAX(CASE WHEN c.extra LIKE '%auto_increment%' THEN 1 ELSE 0 END) AS has_auto_increment "
                + "FROM information_schema.tables t "
                + "LEFT JOIN information_schema.columns c "
                + "ON t.table_schema = c.table_schema AND t.table_name = c.table_name "
                + "WHERE t.table_schema = ? AND t.table_type = 'BASE TABLE' "
                + "GROUP BY t.table_schema, t.table_name, t.auto_increment, t.update_time, "
                + "t.data_length, t.engine, t.table_rows, t.table_comment "
                + "ORDER BY t.table_name";
        try (Connection jdbcConnection = openConnection(connection, password);
             PreparedStatement statement = jdbcConnection.prepareStatement(sql)) {
            statement.setString(1, databaseName);
            try (ResultSet resultSet = statement.executeQuery()) {
                List<DatabaseTableVO> result = new ArrayList<>();
                while (resultSet.next()) {
                    DatabaseTableVO table = new DatabaseTableVO();
                    table.setOwner(resultSet.getString("table_schema").toUpperCase(Locale.ROOT));
                    table.setTableName(resultSet.getString("table_name"));
                    if (resultSet.getInt("has_auto_increment") == 1) {
                        fillAutoIncrement(table, defaultZero(getLongValue(resultSet, "auto_increment")));
                    }
                    Timestamp updateTime = resultSet.getTimestamp("update_time");
                    table.setUpdateTime(updateTime == null ? null : updateTime.toLocalDateTime());
                    table.setDataLength(getLongValue(resultSet, "data_length"));
                    table.setEngine(resultSet.getString("engine"));
                    table.setTableRows(getLongValue(resultSet, "table_rows"));
                    table.setComments(resultSet.getString("table_comment"));
                    result.add(table);
                }
                return result;
            }
        }
    }

    private Long getLongValue(ResultSet resultSet, String columnName) throws Exception {
        long value = resultSet.getLong(columnName);
        return resultSet.wasNull() ? null : value;
    }

    private Long defaultZero(Long value) {
        return value == null ? 0L : value;
    }

    private void fillAutoIncrement(DatabaseTableVO table, Long autoIncrement) {
        table.setAutoIncrementValue(autoIncrement);
        table.setAutoIncrement(autoIncrement);
    }

    private Connection openConnection(DatabaseConnection connection, String password) throws Exception {
        if (StrUtil.isBlank(password)) {
            throw new IllegalArgumentException("数据库密码不能为空");
        }
        return DriverManager.getConnection(MysqlJdbcUrlUtil.build(connection), connection.getUsername(), password);
    }
}
