package cn.fateverse.query.service.impl;

import cn.fateverse.common.core.exception.CustomException;
import cn.fateverse.common.core.result.Result;
import cn.fateverse.common.core.result.page.TableDataInfo;
import cn.fateverse.common.decrypt.service.EncryptService;
import cn.fateverse.query.entity.*;
import cn.fateverse.query.entity.bo.TopologySelect;
import cn.fateverse.query.entity.vo.*;
import cn.fateverse.query.mapper.*;
import cn.fateverse.query.service.*;
import cn.fateverse.query.entity.dto.TableRelationalMappingDto;
import cn.fateverse.query.entity.dto.TopoDto;
import cn.fateverse.query.entity.dto.UniConDto;
import cn.fateverse.query.entity.topology.TopologyBo;
import com.alibaba.fastjson2.JSON;
//import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Clay
 * @date 2023-07-21
 */
@Slf4j
@Service
public class TopologySearchServiceImpl extends SearchService implements TopologySearchService {
    //表格
    private final TableMapper tableMapper;
    //表格列信息
    private final TableColumnMapper tableColumnMapper;
    //拓扑分析服务
    private final TopologyAnalyzeService topologyAnalyzeService;
    //表格关系映射
    private final TableRelationalMappingMapper relationalMappingMapper;

    public TopologySearchServiceImpl(EncryptService encryptService,
                                     TableMapper tableMapper,
                                     UniConMapper uniConMapper,
                                     UniQueryMapper uniQueryMapper,
                                     UniColumnMapper uniColumnMapper,
                                     TableColumnMapper tableColumnMapper,
                                     TopologyAnalyzeService topologyAnalyzeService,
                                     DynamicDataSearchService dynamicDataSearchService,
                                     TableRelationalMappingMapper relationalMappingMapper,
                                     DynamicDataSourceTableService dynamicDataSourceTableService) {
        super(encryptService, uniConMapper, uniColumnMapper, uniQueryMapper, dynamicDataSearchService, dynamicDataSourceTableService);
        this.tableMapper = tableMapper;
        this.tableColumnMapper = tableColumnMapper;
        this.topologyAnalyzeService = topologyAnalyzeService;
        this.relationalMappingMapper = relationalMappingMapper;
    }

    @Override
    public TopoVo search(Long queryId) {
        UniQuery uniQuery = uniQueryMapper.selectById(queryId);
        List<Table> tableList = tableMapper.selectListByDataSourceId(uniQuery.getDataSourceId());
        if (null == tableList || tableList.isEmpty()) {
            return new TopoVo();
        }
        List<Long> tableIds = tableList.stream().map(Table::getTableId).collect(Collectors.toList());
        List<TableColumn> tableColumns = tableColumnMapper.selectByTableIds(tableIds);
        Map<Long, List<TableColumnVo>> tableColumMap;
        if (null == tableColumns || tableColumns.isEmpty()) {
            tableColumMap = new HashMap<>();
        } else {
            tableColumMap = tableColumns.stream().map(TableColumnVo::toTableColumnVo).collect(Collectors.groupingBy(TableColumnVo::getTableId));
        }
        List<TableRelationalMapping> relationalMappings = relationalMappingMapper.selectByMainIds(tableIds);
        List<TableRelationalMappingDto> mappingDtoList = relationalMappings.stream().map(TableRelationalMappingDto::toTableRelationalMappingDto).collect(Collectors.toList());
        List<TableTopoVo> topoList = tableList.stream().map(table ->
                TableTopoVo.builder()
                        .tableId(table.getTableId())
                        .tableName(table.getTableName())
                        .tableComment(table.getTableComment())
                        .columns(tableColumMap.get(table.getTableId()))
                        .build()).collect(Collectors.toList());
        return TopoVo.builder()
                .relational(mappingDtoList)
                .tableList(topoList)
                .topJson(uniQuery.getTopJson())
                .build();
    }


    @Override
    public Integer saveData(TopoDto topo) {
        UniQuery query = new UniQuery();
        query.setId(topo.getLongQueryId());
        query.setTopJson(topo.getTopJson());
        return uniQueryMapper.update(query);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<CustomQueryResult> preview(TopoDto topo) {
        TopologyBo topologyBo = topologyAnalyzeService.initTopologyJson(topo.getTopJson());
        TopologySelect topologySelect = getTopologySelect(topo, topologyBo);
        UniQuery query = uniQueryMapper.selectSampleById(topo.getLongQueryId());
        TableDataInfo<Map<String, Object>> mapTableDataInfo = dynamicDataSourceTableService.uniQueryTopology(topologySelect, query.getDataSourceId());
        //设置已经预览
        query.setPreview(Boolean.TRUE);
        //设置查询的关键词
        setQuery(topo, query, topologySelect);
        //更新查询
        return previewCustomQueryResult(topologySelect.getUniCons(), topologySelect.getUniColumns(), query, mapTableDataInfo);
    }

    /**
     * 获取到topo查询对象
     *
     * @param topo       拓扑对象
     * @param topologyBo 拓扑查询业务对象
     * @return 拓扑查询查询对象
     */
    private TopologySelect getTopologySelect(TopoDto topo, TopologyBo topologyBo) {
        TopologySelect topologySelect;
        if (topologyBo.getNodes().size() == 1) {
            topologySelect = topologyAnalyzeService.singleTableAnalyze(topologyBo.getNodes().get(0), topo.getLongQueryId());
            topologySelect.setSingle(Boolean.TRUE);
        } else {
            topologySelect = topologyAnalyzeService.multiListAnalyze(topologyBo, topo.getLongQueryId());
            topologySelect.setSingle(Boolean.FALSE);
        }
        return topologySelect;
    }

    @Override
//    @GlobalTransactional
    public void publish(TopoDto topo) {
        UniQuery query = uniQueryMapper.selectSampleById(topo.getLongQueryId());
        if (query.getPublish()) {
            throw new CustomException("状态异常");
        }
        TopologyBo topologyBo = topologyAnalyzeService.initTopologyJson(topo.getTopJson());
        TopologySelect select = getTopologySelect(topo, topologyBo);
        query.setPublish(Boolean.TRUE);
        setQuery(topo, query, select);
        doPublish(query, topo.getMenuId(), select.getUniCons(), select.getUniColumns());
    }


    /**
     * 设置query对象
     *
     * @param topo   拓扑图对象
     * @param query  query对象
     * @param select 查询信息对象
     */
    private void setQuery(TopoDto topo, UniQuery query, TopologySelect select) {
        //设置查询的关键词
        query.setSelectKey(select.getSelectKey());
        //设置表格的基本信息
        query.setTableInfo(select.getTableInfo());
        //设置表格的关联关系
        query.setRelevance(JSON.toJSONString(select.getRelevance()));
        //设置拓扑图的json数据
        query.setTopJson(topo.getTopJson());
        //是否为单表查询
        query.setSingle(select.getSingle());
    }

    @Override
    public TableDataInfo<Map<String, Object>> previewData(List<UniConDto> list, Long queryId) {
        return super.searchData(list, queryId);
    }

}
