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.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.vo.CustomQueryResult;
import cn.fateverse.query.entity.dto.SqlDto;
import cn.fateverse.query.entity.dto.UniConDto;
import cn.fateverse.query.entity.vo.SqlInfoVo;
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.SearchService;
import cn.fateverse.query.service.SqlSearchService;
//import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Clay
 * @date 2023-08-09
 */
@Slf4j
@Service
public class SqlSearchServiceImpl extends SearchService implements SqlSearchService {


    public SqlSearchServiceImpl(EncryptService encryptService,
                                UniConMapper uniConMapper,
                                UniQueryMapper uniQueryMapper,
                                UniColumnMapper uniColumnMapper,
                                DynamicDataSearchService dynamicDataSearchService,
                                DynamicDataSourceTableService dynamicDataSourceTableService) {
        super(encryptService, uniConMapper, uniColumnMapper, uniQueryMapper, dynamicDataSearchService, dynamicDataSourceTableService);
    }

    @Override
    public SqlInfoVo search(Long queryId) {
        UniQuery query = uniQueryMapper.selectById(queryId);
        List<UniCon> uniConList = uniConMapper.selectByQueryId(queryId);
        List<UniColumn> uniColumns = uniColumnMapper.selectByQueryId(queryId);
        return SqlInfoVo.builder()
                .uqName(query.getUqName())
                .uqDescribe(query.getUqDescribe())
                .queryId(queryId.toString())
                .uniSql(query.getUqSql())
                .uniCons(uniConList)
                .uniColumns(uniColumns)
                .build();
    }

    @Override
    public void saveData(SqlDto sqlDto) {
        UniQuery query = new UniQuery();
        query.setId(sqlDto.getLongQueryId());
        query.setUqSql(sqlDto.getUniSql());
        uniQueryMapper.update(query);
        List<UniCon> uniCons = sqlDto.getUniCons();
        if (null != uniCons && !uniCons.isEmpty()) {
            uniCons.forEach(uniCon -> {
                uniCon.setUcId(null);
                uniCon.setUqId(query.getId());
            });
            uniConMapper.batchDelete(query.getId());
            uniConMapper.batchInsert(uniCons);
        }
        List<UniColumn> uniColumns = sqlDto.getUniColumns();
        if (null != uniColumns && !uniColumns.isEmpty()) {
            uniColumns.forEach(column -> column.setQueryId(query.getId()));
            uniColumnMapper.batchDeleteByQueryId(query.getId());
            uniColumnMapper.batchInsert(uniColumns);
        }
    }

    @Override
    public Result<CustomQueryResult> preview(SqlDto sqlDto) {
        String checkSql = sqlDto.getUniSql().toLowerCase();
        if (containsDDL(checkSql)) {
            throw new CustomException("字符串中包含DDL语句");
        }
        if (containsDML(checkSql)) {
            throw new CustomException("字符串中包含DML语句");
        }
        UniQuery query = uniQueryMapper.selectSampleById(sqlDto.getLongQueryId());
        SqlSelect select = new SqlSelect();
        select.setSelectSql(sqlDto.getUniSql());
        select.setUniCons(new ArrayList<>());
        TableDataInfo<Map<String, Object>> dataInfo = dynamicDataSourceTableService.uniQuerySql(select, query.getDataSourceId());
        //设置已经预览
        query.setPreview(Boolean.TRUE);
        //设置查询sql
        query.setUqSql(sqlDto.getUniSql());
        return previewCustomQueryResult(sqlDto.getUniCons(), sqlDto.getUniColumns(), query, dataInfo);
    }

    public boolean containsDDL(String sqlString) {
        String ddlPattern = "\\b(create|alter|drop|truncate)\\b";
        Pattern pattern = Pattern.compile(ddlPattern, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(sqlString);
        return matcher.find();
    }

    public boolean containsDML(String sqlString) {
        String dmlPattern = "\\b(delete|update|insert)\\b";
        Pattern pattern = Pattern.compile(dmlPattern, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(sqlString);
        return matcher.find();
    }

    @Override
//    @GlobalTransactional
    public void publish(SqlDto sqlDto) {
        UniQuery query = uniQueryMapper.selectSampleById(sqlDto.getLongQueryId());
        if (query.getPublish()) {
            throw new CustomException("状态异常");
        }
        query.setPublish(Boolean.TRUE);
        doPublish(query, sqlDto.getMenuId(), sqlDto.getUniCons(), sqlDto.getUniColumns());
    }

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

}
