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

import cn.hutool.core.util.ObjectUtil;
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.DatabaseFieldDTO;
import cn.stylefeng.team.meta.api.pojo.db.DatabaseTableDTO;
import cn.stylefeng.team.meta.api.pojo.db.TableDescription;
import cn.stylefeng.team.meta.db.sdk.config.DataSourceConfig;
import cn.stylefeng.team.meta.db.sdk.config.builder.ConfigBuilder;
import cn.stylefeng.team.meta.db.sdk.config.querys.DecoratorDbQuery;
import cn.stylefeng.team.meta.db.sdk.jdbc.DatabaseMetaDataWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
public abstract class IDatabaseQuery {

    protected final ConfigBuilder configBuilder;

    protected final DataSourceConfig dataSourceConfig;

    public IDatabaseQuery(@NotNull ConfigBuilder configBuilder) {
        this.configBuilder = configBuilder;
        this.dataSourceConfig = configBuilder.getDataSourceConfig();
    }

    @NotNull
    public abstract List<DatabaseTableDTO> queryTables();

    @NotNull
    public abstract List<DatabaseTableDTO> queryTablesByTableNameList(List<String> tableNameList);

    @NotNull
    public abstract List<String> queryTableNames();

    @NotNull
    public abstract List<TableDescription> queryTableDescriptions();

    public static class DefaultDatabaseQuery extends IDatabaseQuery {

        private final DecoratorDbQuery dbQuery;

        public DefaultDatabaseQuery(@NotNull ConfigBuilder configBuilder) {
            super(configBuilder);
            this.dbQuery = new DecoratorDbQuery(dataSourceConfig);
        }

        @NotNull
        @Override
        public List<DatabaseTableDTO> queryTables() {

            List<DatabaseTableDTO> genDatabaseTableDTOList = new ArrayList<>();

            try {
                dbQuery.query(dbQuery.tablesSql(), result -> {

                    DatabaseTableDTO genDatabaseTableDto = new DatabaseTableDTO();

                    String tableName = result.getStringResult(dbQuery.tableName());
                    if (StringUtils.isNotBlank(tableName)) {

                        genDatabaseTableDto.setTableName(tableName);

                        String tableComment = result.getTableComment();
                        if (StringUtils.isNotBlank(tableComment)) {
                            genDatabaseTableDto.setDescription(tableComment);
                        }

                        if (!("VIEW".equals(tableComment)) && !tableName.startsWith("BIN$")) {

                            List<DatabaseFieldDTO> genDatabaseFieldDtoList = getFieldList(tableName);
                            if (ObjectUtil.isNotEmpty(genDatabaseFieldDtoList)) {
                                genDatabaseTableDto.setGenDatabaseFieldDtoList(genDatabaseFieldDtoList);
                            }
                            genDatabaseTableDTOList.add(genDatabaseTableDto);
                        }
                    }
                });
                return genDatabaseTableDTOList;
            } catch (SQLException e) {
                log.error("代码生成错误", e);
                throw new GeneratorException(DatabaseMetadataExceptionEnum.GEN_DATABASE_LINK_FAIL);
            } catch (Exception e) {
                log.error("代码生成错误", e);
                throw new GeneratorException(DatabaseMetadataExceptionEnum.GEN_DATABASE_TABLE_FAIL);
            } finally {

                dbQuery.closeConnection();
            }
        }

        @NotNull
        @Override
        public List<DatabaseTableDTO> queryTablesByTableNameList(List<String> tableNameList) {

            List<DatabaseTableDTO> genDatabaseTableDTOList = new ArrayList<>();

            try {
                dbQuery.query(dbQuery.tablesSql(), result -> {

                    DatabaseTableDTO genDatabaseTableDto = new DatabaseTableDTO();

                    String tableName = result.getStringResult(dbQuery.tableName());

                    if (StringUtils.isNotBlank(tableName)) {

                        for (String screenTableName : tableNameList) {
                            if (tableName.equals(screenTableName)) {

                                genDatabaseTableDto.setTableName(tableName);

                                String tableComment = result.getTableComment();
                                if (StringUtils.isNotBlank(tableComment)) {
                                    genDatabaseTableDto.setDescription(tableComment);
                                }

                                if (!("VIEW".equals(tableComment)) && !tableName.startsWith("BIN$")) {

                                    List<DatabaseFieldDTO> genDatabaseFieldDtoList = getFieldList(tableName);
                                    if (ObjectUtil.isNotEmpty(genDatabaseFieldDtoList)) {
                                        genDatabaseTableDto.setGenDatabaseFieldDtoList(genDatabaseFieldDtoList);
                                    }
                                    genDatabaseTableDTOList.add(genDatabaseTableDto);
                                }
                            }
                        }
                    }
                });
                return genDatabaseTableDTOList;
            } catch (SQLException e) {
                throw new GeneratorException(DatabaseMetadataExceptionEnum.GEN_DATABASE_LINK_FAIL);
            } catch (Exception e) {
                throw new GeneratorException(DatabaseMetadataExceptionEnum.GEN_DATABASE_TABLE_FAIL);
            } finally {

                dbQuery.closeConnection();
            }
        }

        @NotNull
        @Override
        public List<String> queryTableNames() {
            List<TableDescription> tableDescriptions = queryTableDescriptions();
            return tableDescriptions.stream().map(TableDescription::getTableCode).collect(Collectors.toList());
        }

        @Override
        public List<TableDescription> queryTableDescriptions() {

            List<TableDescription> tableNameList = new ArrayList<>();
            try {
                dbQuery.query(dbQuery.tablesSql(), result -> {

                    String tableName = result.getStringResult(dbQuery.tableName());

                    String tableComment = result.getTableComment();

                    TableDescription tableDescription = new TableDescription();
                    tableDescription.setTableName(tableComment);
                    tableDescription.setTableCode(tableName);

                    if (StringUtils.isNotBlank(tableName)) {

                        if (!("VIEW".equals(tableComment)) && !tableName.startsWith("BIN$")) {
                            tableNameList.add(tableDescription);
                        }
                    }
                });
                return tableNameList;
            } catch (SQLException e) {
                throw new GeneratorException(DatabaseMetadataExceptionEnum.GEN_DATABASE_LINK_FAIL);
            } catch (Exception e) {
                throw new GeneratorException(DatabaseMetadataExceptionEnum.GEN_DATABASE_TABLE_FAIL);
            } finally {

                dbQuery.closeConnection();
            }

        }

        private List<DatabaseFieldDTO> getFieldList(String tableName) {
            try {
                return new DatabaseMetaDataWrapper(dbQuery.getConnection()).getFieldList(null, dataSourceConfig.getSchemaName(), tableName);
            } catch (SQLException e) {

                dbQuery.closeConnection();
                throw new GeneratorException(DatabaseMetadataExceptionEnum.GEN_DATABASE_FIELD_FAIL);
            }
        }
    }

}
