package com.ebts.generator.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.ebts.common.constant.ReturnConstants;
import com.ebts.common.core.entity.Result;
import com.ebts.common.core.entity.entity.Menu;
import com.ebts.common.utils.SecurityUtils;
import com.ebts.generator.dao.QueryDao;
import com.ebts.generator.dao.UniColumnInfoDao;
import com.ebts.generator.dao.UniQueryDao;
import com.ebts.generator.entity.UniColumnInfo;
import com.ebts.generator.entity.UniCon;
import com.ebts.generator.entity.UniQuery;
import com.ebts.generator.service.QueryService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Author 18209
 * Date 2021/1/30 18:54
 * Version 1.0
 */
@Service
@Slf4j
public class QueryServiceImpl implements QueryService {

    @Resource
    private QueryDao queryDao;

    @Resource
    private UniQueryDao uniQueryDao;

    @Resource
    private UniColumnInfoDao uniColumnInfoDao;


    /**
     * 查询万能查询的基本信息和条件信息
     */
    @Override
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public Result<UniQuery> selectQueryById(Long id) {
        UniQuery uniQuery = queryDao.selectQueryInfo(id);
        if (uniQuery != null) {
            return Result.ok(uniQuery);
        } else {
            return Result.info(ReturnConstants.RESULT_EMPTY);
        }
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public Result<Integer> Release(UniQuery uniQuery) {
        Integer isRelease = queryDao.Release(uniQuery.getId());
        if ((isRelease == 1 && uniQuery.getIsRelease() == 2) || (isRelease == 2 && uniQuery.getIsRelease() == 1)) {
            if (uniQuery.getIsRelease() == 1) {
                UniQuery query = uniQueryDao.selectUniQueryById(uniQuery.getId());
                Menu Menu = new Menu(query.getId(), query.getUqName(), SecurityUtils.getUserId());
                Integer insermenu = queryDao.insertMenu(Menu);
                if (insermenu == 0) {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Result.error(ReturnConstants.OP_ERROR);
                }
            } else {
                Integer deleteMenu = queryDao.deleteMenu("data/" + uniQuery.getId());
                if (deleteMenu == 0) {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Result.error(ReturnConstants.OP_ERROR);
                }
            }
            Integer release = queryDao.changeRelease(uniQuery);
            if (release > 0) {
                return Result.ok();
            } else {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.error(ReturnConstants.OP_ERROR);
            }
        } else {
            return Result.error(ReturnConstants.STATE_ERROR);
        }
    }

    /**
     * 更新万能查询基本信息和条件
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Result<Integer> updateQueryInfo(UniQuery uniQuery) {
        uniQueryDao.updateUniQuery(uniQuery);
        if (uniQuery.getUniCons() != null && uniQuery.getUniCons().size() > 0) {
            queryDao.deleteUniCon(uniQuery.getId());
            queryDao.insertUniCon(uniQuery.getUniCons());
            resetColumnInfo(uniQuery);
        }
        return Result.ok();
    }

    void resetColumnInfo(UniQuery uniQuery){
        List<UniColumnInfo> infoList = uniQuery.getInfoList().stream().peek(info ->
                info.setQueryId(uniQuery.getId())
        ).collect(Collectors.toList());
        uniColumnInfoDao.deleteUniColumnInfo(uniQuery.getId());
        uniColumnInfoDao.insertUniColumnInfo(infoList);
    }

    @Override
    public Result<List<Map<String, Object>>> previewQuery(UniQuery uniQuery) {
        StringBuilder sql = new StringBuilder(uniQuery.getUqSql().toLowerCase());
        List<UniCon> uniConList = uniQuery.getUniCons();
        if (sql.toString().contains("insert") || sql.toString().contains("delete ") || sql.toString().contains("update ") ||
                sql.toString().contains("drop ") || sql.toString().contains("database ") || sql.toString().contains("create ") ||
                sql.toString().contains("view ") || sql.toString().contains("alter ") || sql.toString().contains("gen_")) {
            return Result.error("sql语句含有insert,delete,update,drop,database,view,alter,gen_等特殊字符!");
        }
        if (uniConList.size() > 0) {
            sql.append(" where 1 = 1");
            for (UniCon uniCon : uniConList) {
                if (!uniCon.getUcMock().equals("") && uniCon.getUcMock() != null) {
                    sql.append(conversionPreview(uniCon));
                }
            }
        }
        List<Map<String, Object>> dataMap = queryDao.UniQuery(sql.toString());
        return Result.ok(dataMap);
    }

    /**
     * 预览模式下拼接sql
     *
     * @param uniCon
     * @return
     */
    public String conversionPreview(UniCon uniCon) {
        String sql = " and ";
        switch (uniCon.getUcCon()) {
            case "EQ":
                sql += uniCon.getUcKey() + " = '" + uniCon.getUcMock() + "'";
                break;
            case "NE":
                sql += uniCon.getUcKey() + " != '" + uniCon.getUcMock() + "'";
                break;
            case "GT":
                sql += uniCon.getUcKey() + " > '" + uniCon.getUcMock() + "'";
                break;
            case "GTE":
                sql += uniCon.getUcKey() + " >= '" + uniCon.getUcMock() + "'";
                break;
            case "LT":
                sql += uniCon.getUcKey() + " < '" + uniCon.getUcMock() + "'";
                break;
            case "LTE":
                sql += uniCon.getUcKey() + " <= '" + uniCon.getUcMock() + "'";
                break;
            case "LIKE":
                sql += uniCon.getUcKey() + " like '%" + uniCon.getUcMock() + "%'";
                break;
            case "BETWEEN":
                try {
                    JSONObject jsonObject = JSONObject.parseObject(uniCon.getUcMock());
                    if (uniCon.getUcType().equals("input")) {
                        Object begin = jsonObject.get("begin");
                        Object end = jsonObject.get("end");
                        if (begin != null && end != null) {
                            sql += uniCon.getUcKey() + " between '" + begin + "' AND '" + end + "'";
                        } else {
                            sql = "";
                        }
                    } else if (uniCon.getUcType().equals("datetime")) {
                        Object startTime = jsonObject.get("startTime");
                        Object endTime = jsonObject.get("endTime");
                        sql += uniCon.getUcKey() + " between '" + startTime + "' AND '" + endTime + "'";
                    }
                } catch (RuntimeException e) {
                    log.error(e.getMessage());
                    sql = "";
                }
                break;
        }
        return sql;
    }
}
