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.security.utils.SecurityUtils;
import cn.fateverse.query.constant.QueryConstant;
import cn.fateverse.query.entity.UniColumn;
import cn.fateverse.query.entity.UniCon;
import cn.fateverse.query.entity.UniQuery;
import cn.fateverse.query.entity.bo.SqlSelect;
import cn.fateverse.query.entity.bo.TopologySelect;
import cn.fateverse.query.entity.vo.CustomQueryResult;
import cn.fateverse.query.entity.dto.SearchInfo;
import cn.fateverse.query.entity.vo.UniConVo;
import cn.fateverse.query.mapper.UniColumnMapper;
import cn.fateverse.query.mapper.UniConMapper;
import cn.fateverse.query.mapper.UniQueryMapper;
import cn.fateverse.query.service.DynamicDataSearchService;
import cn.fateverse.query.service.DynamicDataSourceTableService;
import cn.fateverse.query.service.PageService;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

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

/**
 * @author Clay
 * @date 2023-08-05
 */
@Slf4j
@Service
public class PageServiceImpl implements PageService {

    private final UniConMapper uniConMapper;

    private final UniQueryMapper uniQueryMapper;

    private final UniColumnMapper uniColumnMapper;

    private final DynamicDataSearchService dynamicDataSearchService;

    private final DynamicDataSourceTableService dynamicDataSourceTableService;

    public PageServiceImpl(UniConMapper uniConMapper,
                           UniQueryMapper uniQueryMapper,
                           UniColumnMapper uniColumnMapper,
                           DynamicDataSearchService dynamicDataSearchService, DynamicDataSourceTableService dynamicDataSourceTableService) {
        this.uniConMapper = uniConMapper;
        this.uniQueryMapper = uniQueryMapper;
        this.uniColumnMapper = uniColumnMapper;
        this.dynamicDataSearchService = dynamicDataSearchService;
        this.dynamicDataSourceTableService = dynamicDataSourceTableService;
    }


    @Override
    public Result<CustomQueryResult> searchQueryInfoAndData(Long queryId) {
        checkPermissions(queryId);
        UniQuery query = uniQueryMapper.selectSampleById(queryId);
        if (!query.getPublish()) {
            return Result.error("当前查询状态有误");
        }
        if (query.getType() == 1) {
            return getSqlQueryData(queryId, query);
        } else {
            return getTopoQueryData(queryId, query);
        }
    }

    /**
     * 获取sql查询结果
     *
     * @param queryId 自定义查询id
     * @param query   自定义查询
     * @return 组合数据
     */
    private Result<CustomQueryResult> getSqlQueryData(Long queryId, UniQuery query) {
        SqlSelect select = new SqlSelect();
        select.setSelectSql(query.getUqSql());
        select.setUniCons(new ArrayList<>());
        TableDataInfo<Map<String, Object>> dataInfo = dynamicDataSourceTableService.uniQuerySql(select, query.getDataSourceId());
        return combinationQueryResult(queryId, dataInfo);
    }

    /**
     * 获取拓扑图的数据
     *
     * @param queryId 自定义查询id
     * @param query   自定义查询
     * @return 组合数据
     */
    private Result<CustomQueryResult> getTopoQueryData(Long queryId, UniQuery query) {
        TopologySelect select = TopologySelect.builder()
                .selectKey(query.getSelectKey())
                .tableInfo(query.getTableInfo())
                .single(query.getSingle())
                .uniCons(new ArrayList<>())
                .build();
        if (!query.getSingle()) {
            List<String> relevance = JSON.parseArray(query.getRelevance(), String.class);
            select.setRelevance(relevance);
        }
        TableDataInfo<Map<String, Object>> tableDataInfo = dynamicDataSourceTableService.uniQueryTopology(select, query.getDataSourceId());
        return combinationQueryResult(queryId, tableDataInfo);
    }

    /**
     * 组合查询结果数据
     *
     * @param queryId  自定义查询id
     * @param dataInfo 结果数据
     * @return 组合数据
     */
    private Result<CustomQueryResult> combinationQueryResult(Long queryId, TableDataInfo<Map<String, Object>> dataInfo) {
        List<UniColumn> uniColumns = uniColumnMapper.selectByQueryId(queryId);
        List<UniCon> uniConList = uniConMapper.selectByQueryId(queryId);
        List<UniConVo> uniConVoList;
        if (null == uniConList || uniConList.isEmpty()) {
            uniConVoList = new ArrayList<>();
        } else {
            uniConVoList = uniConList.stream().map(UniCon::toUcConVo).collect(Collectors.toList());
        }
        CustomQueryResult customQueryResult = CustomQueryResult.builder()
                .uniColumns(uniColumns)
                .uniCons(uniConVoList)
                .table(dataInfo)
                .build();
        return Result.ok(customQueryResult);
    }


    @Override
    public TableDataInfo<Map<String, Object>> searchQueryData(SearchInfo searchInfo) {
        checkPermissions(searchInfo.getLongQueryId());
        UniQuery query = uniQueryMapper.selectSampleById(searchInfo.getLongQueryId());
        if (!query.getPublish()) {
            throw new CustomException("当前状态有误!");
        }
        return dynamicDataSearchService.searchData(searchInfo.getList(), query);
    }


    private void checkPermissions(Long queryId) {
        if (!SecurityUtils.isAdmin()) {
            Set<String> permissions = SecurityUtils.getPermissions();
            if (null != permissions && !permissions.contains(QueryConstant.PERMISSIONS_KEY + queryId)) {
                throw new CustomException("您无权限访问!");
            }
        }
    }


}
