package cn.stylefeng.team.meta.db.sdk;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.roses.kernel.rule.enums.DbTypeEnum;
import cn.stylefeng.roses.kernel.rule.util.DatabaseTypeUtil;
import cn.stylefeng.team.meta.api.DatabaseMetadataApi;
import cn.stylefeng.team.meta.api.exception.GeneratorException;
import cn.stylefeng.team.meta.api.exception.enums.DatabaseMetadataExceptionEnum;
import cn.stylefeng.team.meta.api.pojo.db.DatabaseMetadataRequest;
import cn.stylefeng.team.meta.api.pojo.db.DatabaseTableDTO;
import cn.stylefeng.team.meta.api.pojo.db.TableDescription;
import cn.stylefeng.team.meta.api.util.DbNameReplaceUtil;
import cn.stylefeng.team.meta.db.sdk.config.DataSourceConfig;
import cn.stylefeng.team.meta.db.sdk.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.stereotype.Service;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

@Service
public class DatabaseMetadataService implements DatabaseMetadataApi {

    @Override
    public List<String> getDatabaseNameList(DatabaseMetadataRequest databaseMetadataRequest) {

        List<String> databaseNameList = new ArrayList<>();

        DataSourceConfig dataSourceConfig = getDataSourceConfig(databaseMetadataRequest);

        Connection connection = dataSourceConfig.getConn();
        try {

            DatabaseMetaData metaData = connection.getMetaData();

            if (DbTypeEnum.ORACLE.equals(DatabaseTypeUtil.getDbType(dataSourceConfig.getUrl()))) {
                ResultSet schemas = metaData.getSchemas();
                while (schemas.next()) {
                    String tem = schemas.getString("TABLE_SCHEM");
                    databaseNameList.add(tem);
                }
            }

            else {
                ResultSet tables = metaData.getCatalogs();
                while (tables.next()) {
                    String databaseName = tables.getString("TABLE_CAT");
                    databaseNameList.add(databaseName);
                }
            }

            return databaseNameList;
        } catch (SQLException e) {
            throw new GeneratorException(DatabaseMetadataExceptionEnum.GEN_DATABASE_LINK_FAIL);
        } finally {
            IoUtil.close(connection);
        }
    }

    @Override
    public List<DatabaseTableDTO> getTableList(DatabaseMetadataRequest databaseMetadataRequest) {

        DataSourceConfig dataSourceConfig = getDataSourceConfig(databaseMetadataRequest);

        ConfigBuilder config = new ConfigBuilder(dataSourceConfig);

        return config.getTableList();
    }

    @Override
    public List<TableDescription> getTableNameList(DatabaseMetadataRequest databaseMetadataRequest) {

        if (ObjectUtil.isNotEmpty(databaseMetadataRequest.getDatabaseName())) {
            String newUrl = DbNameReplaceUtil.replaceDatabaseName(databaseMetadataRequest.getDatabaseUrl(), databaseMetadataRequest.getDatabaseName());
            databaseMetadataRequest.setDatabaseUrl(newUrl);
        }

        DataSourceConfig dataSourceConfig = this.getDataSourceConfig(databaseMetadataRequest);
        ConfigBuilder config = new ConfigBuilder(dataSourceConfig);
        return config.getTableDescriptions();
    }

    @Override
    public List<DatabaseTableDTO> getTableListByNameList(DatabaseMetadataRequest databaseMetadataRequest) {

        String newUrl = DbNameReplaceUtil.replaceDatabaseName(databaseMetadataRequest.getDatabaseUrl(), databaseMetadataRequest.getDatabaseName());
        databaseMetadataRequest.setDatabaseUrl(newUrl);

        DataSourceConfig dataSourceConfig = this.getDataSourceConfig(databaseMetadataRequest);
        ConfigBuilder config = new ConfigBuilder(dataSourceConfig);
        return config.getTableList(databaseMetadataRequest.getTableNameList());
    }

    private DataSourceConfig getDataSourceConfig(DatabaseMetadataRequest databaseMetadataRequest) {

        DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder(databaseMetadataRequest.getDatabaseUrl(),
                databaseMetadataRequest.getDatabaseUserName(), databaseMetadataRequest.getDatabasePassword()).build();
        if (StringUtils.isNotBlank(databaseMetadataRequest.getDatabaseSchemaName())) {
            dataSourceConfig.setSchemaName(databaseMetadataRequest.getDatabaseSchemaName());
        }
        return dataSourceConfig;
    }

}
