package cn.fateverse.query.service;

import cn.fateverse.common.core.exception.CustomException;
import cn.fateverse.common.core.result.page.TableDataInfo;
import cn.fateverse.common.mybatis.utils.PageUtils;
import cn.fateverse.query.entity.*;
import cn.fateverse.query.entity.bo.SqlSelect;
import cn.fateverse.query.entity.bo.TableBo;
import cn.fateverse.query.entity.bo.TopologySelect;
import cn.fateverse.query.enums.DynamicSourceEnum;
import cn.fateverse.query.entity.query.DynamicTableQuery;
import cn.fateverse.query.mapper.DynamicDataSourceMapper;
import cn.fateverse.query.mapper.TableMapper;
import com.github.pagehelper.JSqlParser;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.*;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 动态数据源查询数据
 *
 * @author Clay
 * @date 2023-07-16
 */
@Slf4j
@Service
public class DynamicDataSourceTableService {

    private final TableMapper tableMapper;

    private DataSourceManage dataSourceManage;

    private DynamicDataSourceMapper dynamicDataSourceMapper;

    public DynamicDataSourceTableService(TableMapper tableMapper) {
        this.tableMapper = tableMapper;
    }

    /**
     * 查询到表格信息
     *
     * @param query        表格查询对象
     * @param dataSourceId 数据源id
     * @return 动态表格数据
     */
    public TableDataInfo<DynamicTable> searchTableList(DynamicTableQuery query, Long dataSourceId) {
        DynamicSourceEnum dataSourceType = dataSourceManage.getType();
        DynamicPage page = dataSourceType.getDynamicDataSourceFactory().getDynamicPage();
        List<String> tableNameList = new ArrayList<>(tableMapper.selectTableNameByDataSourceId(dataSourceId));
        Map<String, Object> params = dataSourceManage.getType().getDynamicDataSourceFactory().getParams(dataSourceManage);
        List<DynamicTable> dynamicTables = dynamicDataSourceMapper.selectTableList(query, page, tableNameList, params);
        Long count = dynamicDataSourceMapper.selectTableListCount(query, tableNameList, params);
        return PageUtils.convertDataTable(dynamicTables, count);
    }

    /**
     * 根据表格查询到所有的表格信息
     *
     * @param tables       表格名称
     * @param dataSourceId 数据源id
     * @return 完整的表格信息
     */
    public List<TableBo> searchFullTableByTableNames(List<String> tables, Long dataSourceId) {
        Map<String, Object> params = dataSourceManage.getType().getDynamicDataSourceFactory().getParams(dataSourceManage);
        List<Table> tableList = dynamicDataSourceMapper.selectDynamicTableListByNameList(tables, params);
        Map<String, List<TableColumn>> tableColumnListMap = dynamicDataSourceMapper.selectDynamicTableColumnsByNameList(tables, params).stream().collect(Collectors.groupingBy(TableColumn::getRemark));
        return tableList.stream().map(table -> {
            table.setDataSourceId(dataSourceId);
            table.setDataSourceType(dataSourceManage.getType());
            List<TableColumn> tableColumns = tableColumnListMap.get(table.getTableName());
            initColumns(tableColumns);
            return TableBo.builder()
                    .table(table)
                    .columns(tableColumns)
                    .build();
        }).collect(Collectors.toList());
    }

    /**
     * 自定义查询对象
     *
     * @param select       查询对象
     * @param dataSourceId 数据源id
     * @return 表格数据
     */
    public TableDataInfo<Map<String, Object>> uniQueryTopology(TopologySelect select, Long dataSourceId) {
        return uniQueryTopology(select, null, Boolean.TRUE, dataSourceId);
    }

    /**
     * 自定义查询对象(可设置分页信息)
     *
     * @param select       查询对象
     * @param page         分页信息
     * @param paging       是否分页
     * @param dataSourceId 数据源id
     * @return 表格数据
     */
    public TableDataInfo<Map<String, Object>> uniQueryTopology(TopologySelect select, DynamicPage page, Boolean paging, Long dataSourceId) {
        DynamicPage dynamicPage = getDynamicPage(page, paging);
        List<Map<String, Object>> topologyData = null;
        Long count = null;
        if (select.getSingle()) {
            topologyData = dynamicDataSourceMapper.uniSingleQueryTopology(select, dynamicPage);
            count = dynamicDataSourceMapper.uniSingleQueryTopologyCount(select);
        } else {
            topologyData = dynamicDataSourceMapper.uniMultiListQueryTopology(select, dynamicPage);
            count = dynamicDataSourceMapper.uniMultiListQueryTopologyCount(select);
        }
        return getMapTableDataInfo(topologyData, count);
    }

    /**
     * 初始化列信息
     *
     * @param tableColumns 表格列数据
     */
    private void initColumns(List<TableColumn> tableColumns) {
        tableColumns.forEach(tableColumn -> {
            tableColumn.setUse(Boolean.TRUE);
        });
    }

    /**
     * sql自定义查询
     *
     * @param select       查询信息
     * @param dataSourceId 数据源id
     * @return 查询结果信息
     */
    public TableDataInfo<Map<String, Object>> uniQuerySql(SqlSelect select, Long dataSourceId) {
        return uniQuerySql(select, null, Boolean.TRUE, dataSourceId);
    }

    /**
     * 自定义查询对象(可设置分页信息)
     *
     * @param select       查询对象
     * @param page         分页信息
     * @param paging       是否分页
     * @param dataSourceId 数据源id
     * @return 表格数据
     */
    public TableDataInfo<Map<String, Object>> uniQuerySql(SqlSelect select, DynamicPage page, Boolean paging, Long dataSourceId) {
        DynamicPage dynamicPage = getDynamicPage(page, paging);
        List<Map<String, Object>> sqlData = dynamicDataSourceMapper.uniQuerySql(select, dynamicPage);
        setCountSql(select);
        Long count = dynamicDataSourceMapper.uniQuerySqlCount(select);
        return getMapTableDataInfo(sqlData, count);
    }

    /**
     * 获取动态的分页查询信息
     *
     * @param page   分析信息
     * @param paging 是否分页
     * @return 分页对象
     */
    private DynamicPage getDynamicPage(DynamicPage page, Boolean paging) {
        DynamicPage dynamicPage = null;
        if (paging) {
            if (page == null) {
                DynamicSourceEnum dataSourceType = dataSourceManage.getType();
                dynamicPage = dataSourceType.getDynamicDataSourceFactory().getDynamicPage();
            } else {
                dynamicPage = page;
            }
        }
        return dynamicPage;
    }

    /**
     * 获取到表格返回对象
     *
     * @param dataList 表格数据
     * @param count    总数
     * @return 表格对象
     */
    private TableDataInfo<Map<String, Object>> getMapTableDataInfo(List<Map<String, Object>> dataList, Long count) {
        if (null == dataList) {
            dataList = new ArrayList<>();
        }
        TableDataInfo<Map<String, Object>> tableDataInfo = new TableDataInfo<>();
        tableDataInfo.setRows(dataList);
        tableDataInfo.setTotal(count);
        return tableDataInfo;
    }

    /**
     * 获取到查询总数的sql语句
     *
     * @param sqlSelect 查询对象
     */
    private void setCountSql(SqlSelect sqlSelect) {
        JSqlParser jSqlParser = JSqlParser.DEFAULT;
        Statement parse = null;
        try {
            parse = jSqlParser.parse(sqlSelect.getSelectSql());
        } catch (JSQLParserException e) {
            throw new CustomException("sql解析失败!", e);
        }
        Select select = (Select) parse;
        SelectBody selectBody = select.getSelectBody();
        List<SelectItem> COUNT_ITEM = new ArrayList<>();
        COUNT_ITEM.add(new SelectExpressionItem(new Column("count(0)")));
        ((PlainSelect) selectBody).setSelectItems(COUNT_ITEM);
        sqlSelect.setSelectSql(select.toString());
    }


}
