package cn.datax.service.data.market.service;

import cn.datax.common.core.R;
import cn.datax.common.database.DataSourceFactory;
import cn.datax.common.database.DbQuery;
import cn.datax.common.database.constants.DbQueryProperty;
import cn.datax.common.database.core.PageResult;
import cn.datax.common.exception.DataException;
import cn.datax.common.utils.PageUtil;
import cn.datax.common.utils.ThrowableUtil;
import cn.datax.service.data.factory.api.dto.DbSchema;
import cn.datax.service.data.factory.api.entity.DataSourceEntity;
import cn.datax.service.data.factory.api.feign.DataSourceServiceFeign;
import cn.datax.service.data.market.api.dto.FieldRule;
import cn.datax.service.data.market.api.entity.ApiMaskEntity;
import cn.datax.service.data.market.api.entity.DataApiEntity;
import cn.datax.service.data.market.dao.ApiMaskDao;
import cn.datax.service.data.market.factory.AbstractFactory;
import cn.datax.service.data.market.factory.FactoryProducer;
import cn.datax.service.data.market.factory.crypto.Crypto;
import cn.datax.service.data.market.utils.SqlBuilderUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Optional;

@Slf4j
@Service
public class ApiCallEngine {

    @Autowired
    private DataSourceFactory dataSourceFactory;

    @Autowired
    private DataSourceServiceFeign dataSourceServiceFeign;

    @Autowired
    private ApiMaskDao apiMaskDao;

    @Autowired
    private ObjectMapper objectMapper;

    public PageResult<Map<String, Object>> execute(DataApiEntity dataApi, Map<String, Object> params) {
        R sourceResult = dataSourceServiceFeign.getDataSourceById(dataApi.getExecuteConfig().getSourceId());
        if(sourceResult == null || !sourceResult.isSuccess() || ObjectUtil.isEmpty(sourceResult.getData())){
            throw new DataException("API调用查询数据源出错");
        }
        DataSourceEntity dataSource = null;
        try {
            dataSource = objectMapper.readValue(objectMapper.writeValueAsString(sourceResult.getData()), DataSourceEntity.class);
        } catch (JsonProcessingException e) {
        }
        DbSchema dbSchema = dataSource.getDbSchema();
        DbQueryProperty dbQueryProperty = new DbQueryProperty(dataSource.getDbType(), dbSchema.getHost(),
                dbSchema.getUsername(), dbSchema.getPassword(), dbSchema.getPort(), dbSchema.getDbName(), dbSchema.getSid());
        DbQuery dbQuery = dataSourceFactory.createDbQuery(dbQueryProperty);
        // 参数
        Integer pageNum = Optional.ofNullable(params).map(map -> Integer.parseInt(String.valueOf(map.get("pageNum")))).orElse(1);
        Integer pageSize = Optional.ofNullable(params).map(map -> Integer.parseInt(String.valueOf(map.get("pageSize")))).orElse(20);
        PageUtil pageUtil = new PageUtil(pageNum, pageSize);
        Integer offset = pageUtil.getOffset();
        SqlBuilderUtil.SqlFilterResult sqlFilterResult;
        try {
            sqlFilterResult = SqlBuilderUtil.getInstance().applyFilters(dataApi.getExecuteConfig().getSqlText(), params);
        } catch (Exception e) {
            log.error("全局异常信息ex={}, StackTrace={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
            throw new DataException("API调用动态构造SQL语句出错");
        }
        Map<String, Object> acceptedFilters = sqlFilterResult.getAcceptedFilters();
        // 数据脱敏
        List<FieldRule> rules = null;
        ApiMaskEntity apiMaskEntity = apiMaskDao.selectOne(new QueryWrapper<ApiMaskEntity>().eq("api_id", dataApi.getId()));
        if (apiMaskEntity != null) {
            try {
                apiMaskEntity = objectMapper.readValue(objectMapper.writeValueAsString(apiMaskEntity), ApiMaskEntity.class);
            } catch (JsonProcessingException e) {
            }
            rules = apiMaskEntity.getRules();
        }
        PageResult<Map<String, Object>> pageResult;
        try {
            pageResult = dbQuery.queryByPage(sqlFilterResult.getSql(), acceptedFilters, offset, pageSize);
        } catch (Exception e) {
            log.error("全局异常信息ex={}, StackTrace={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
            throw new DataException("API调用查询结果集出错");
        }
        try {
            if (CollUtil.isNotEmpty(rules)){
                // 并行流处理脱敏
                List<FieldRule> finalRules = rules;
                pageResult.getData().parallelStream().forEach(m -> {
                    finalRules.stream().forEach(r -> {
                        if (m.containsKey(r.getFieldName())) {
                            Object obj = m.get(r.getFieldName());
                            if (null != obj){
                                AbstractFactory factory = FactoryProducer.getFactory(r.getCipherType());
                                Crypto crypto = factory.getCrypto(r.getCryptType());
                                String encrypt = crypto.encrypt(String.valueOf(obj));
                                m.put(r.getFieldName(), encrypt);
                            }
                        }
                    });
                });
            }
        } catch (Exception e) {
            log.error("全局异常信息ex={}, StackTrace={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
            throw new DataException("API调用数据脱敏出错");
        }
        pageResult.setPageNum(pageNum).setPageSize(pageSize);
        return pageResult;
    }
}
