package cn.datax.service.data.visual.service.impl;

import cn.datax.common.exception.DataException;
import cn.datax.common.utils.ThrowableUtil;
import cn.datax.service.data.visual.api.dto.SqlParseDto;
import cn.datax.service.data.visual.api.entity.VisualDataSetEntity;
import cn.datax.service.data.visual.api.dto.VisualDataSetDto;
import cn.datax.service.data.visual.service.VisualDataSetService;
import cn.datax.service.data.visual.mapstruct.VisualDataSetMapper;
import cn.datax.service.data.visual.dao.VisualDataSetDao;
import cn.datax.common.base.BaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.parser.SimpleNode;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitorAdapter;
import net.sf.jsqlparser.statement.select.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 数据集信息表 服务实现类
 * </p>
 *
 * @author yuwei
 * @since 2020-07-31
 */
@Slf4j
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class VisualDataSetServiceImpl extends BaseServiceImpl<VisualDataSetDao, VisualDataSetEntity> implements VisualDataSetService {

    @Autowired
    private VisualDataSetDao visualDataSetDao;

    @Autowired
    private VisualDataSetMapper visualDataSetMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public VisualDataSetEntity saveVisualDataSet(VisualDataSetDto visualDataSetDto) {
        VisualDataSetEntity visualDataSet = visualDataSetMapper.toEntity(visualDataSetDto);
        visualDataSetDao.insert(visualDataSet);
        return visualDataSet;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public VisualDataSetEntity updateVisualDataSet(VisualDataSetDto visualDataSetDto) {
        VisualDataSetEntity visualDataSet = visualDataSetMapper.toEntity(visualDataSetDto);
        visualDataSetDao.updateById(visualDataSet);
        return visualDataSet;
    }

    @Override
    public VisualDataSetEntity getVisualDataSetById(String id) {
        VisualDataSetEntity visualDataSetEntity = super.getById(id);
        return visualDataSetEntity;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteVisualDataSetById(String id) {
        visualDataSetDao.deleteById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteVisualDataSetBatch(List<String> ids) {
        visualDataSetDao.deleteBatchIds(ids);
    }

    @Override
    public List<String> sqlAnalyse(SqlParseDto sqlParseDto) {
        String sql = sqlParseDto.getSqlText();
        Statement stmt;
        try {
            stmt = CCJSqlParserUtil.parse(sql);
        } catch (JSQLParserException e) {
            log.error("全局异常信息ex={}, StackTrace={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
            throw new DataException("SQL语法有问题，解析出错");
        }
        List<String> cols = new ArrayList<>();
        if (stmt instanceof Select) {
            stmt.accept(new StatementVisitorAdapter() {
                @Override
                public void visit(Select select) {
                    select.getSelectBody().accept(new SelectVisitorAdapter() {
                        @Override
                        public void visit(PlainSelect plainSelect) {
                            plainSelect.getSelectItems().stream().forEach(selectItem -> {
                                selectItem.accept(new SelectItemVisitorAdapter() {
                                    @Override
                                    public void visit(SelectExpressionItem item) {
                                        String columnName;
                                        if (item.getAlias() == null) {
                                            SimpleNode node = item.getExpression().getASTNode();
                                            Object value = node.jjtGetValue();
                                            if (value instanceof Column) {
                                                columnName = ((Column) value).getColumnName();
                                            } else if (value instanceof Function) {
                                                columnName = value.toString();
                                            } else {
                                                // 增加对select 'aaa' from table; 的支持
                                                columnName = String.valueOf(value);
                                                columnName = columnName.replace("'", "");
                                                columnName = columnName.replace("\"", "");
                                                columnName = columnName.replace("`", "");
                                            }
                                        } else {
                                            columnName = item.getAlias().getName();
                                        }
                                        columnName = columnName.replace("'", "");
                                        columnName = columnName.replace("\"", "");
                                        columnName = columnName.replace("`", "");
                                        cols.add(columnName);
                                    }
                                });
                            });
                        }
                    });
                }
            });
        }
        return cols;
    }
}
