package cn.datax.service.data.market.api.call.service.impl;

import cn.datax.common.core.DataConstant;
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.call.factory.AbstractFactory;
import cn.datax.service.data.market.api.call.factory.FactoryProducer;
import cn.datax.service.data.market.api.call.factory.crypto.Crypto;
import cn.datax.service.data.market.api.call.service.ApiCallService;
import cn.datax.service.data.market.api.call.utils.SqlBuilderUtil;
import cn.datax.service.data.market.api.call.utils.ThreadUtil;
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.api.feign.ApiMaskServiceFeign;
import cn.datax.service.data.market.api.feign.DataApiServiceFeign;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
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 ApiCallServiceImpl implements ApiCallService {

    @Autowired
    private DataSourceFactory dataSourceFactory;

    @Autowired
    private DataSourceServiceFeign dataSourceServiceFeign;

    @Autowired
    private DataApiServiceFeign dataApiServiceFeign;

    @Autowired
    private ApiMaskServiceFeign apiMaskServiceFeign;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public PageResult<Map<String, Object>> apiCall() {
        R apiResult = dataApiServiceFeign.getDataApiById(ThreadUtil.getInstance().get().getApiId());
        if(apiResult == null || !apiResult.isSuccess() || ObjectUtil.isEmpty(apiResult.getData())){
            ThreadUtil.getInstance().get().setStatus(DataConstant.EnableState.DISABLE.getKey());
            ThreadUtil.getInstance().get().setMsg("API调用查询数据API{" + ThreadUtil.getInstance().get().getApiId() + "}出错");
            throw new DataException("API调用查询数据API出错");
        }
        DataApiEntity dataApiEntity = null;
        try {
            dataApiEntity = objectMapper.readValue(objectMapper.writeValueAsString(apiResult.getData()), DataApiEntity.class);
        } catch (JsonProcessingException e) {
        }
        R sourceResult = dataSourceServiceFeign.getDataSourceById(dataApiEntity.getExecuteConfig().getSourceId());
        if(sourceResult == null || !sourceResult.isSuccess() || ObjectUtil.isEmpty(sourceResult.getData())){
            ThreadUtil.getInstance().get().setStatus(DataConstant.EnableState.DISABLE.getKey());
            ThreadUtil.getInstance().get().setMsg("API调用查询数据源{"+dataApiEntity.getExecuteConfig().getSourceId()+"}出错");
            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);
        // 接收参数
        Map<String, Object> params = null;
        try {
            params = objectMapper.readValue(ThreadUtil.getInstance().get().getCallerParams(), Map.class);
        } catch (JsonProcessingException e) {
        }
        // 分页参数
        Integer pageNum = (Integer) Optional.ofNullable(params.get("pageNum")).orElse(1);
        Integer pageSize = (Integer) Optional.ofNullable(params.get("pageSize")).orElse(20);
        PageUtil pageUtil = new PageUtil(pageNum, pageSize);
        Integer offset = pageUtil.getOffset();
        SqlBuilderUtil.SqlFilterResult sqlFilterResult;
        try {
            sqlFilterResult = SqlBuilderUtil.getInstance().applyFilters(dataApiEntity.getExecuteConfig().getSqlText(), params);
        } catch (Exception e) {
            log.error("全局异常信息ex={}, StackTrace={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
            ThreadUtil.getInstance().get().setStatus(DataConstant.EnableState.DISABLE.getKey());
            ThreadUtil.getInstance().get().setMsg(e.getMessage());
            throw new DataException("API调用动态构造SQL语句出错");
        }
        Map<String, Object> acceptedFilters = sqlFilterResult.getAcceptedFilters();
        // 数据脱敏
        List<FieldRule> rules = null;
        R maskResult = apiMaskServiceFeign.getApiMaskByApiId(ThreadUtil.getInstance().get().getApiId());
        if(maskResult != null && maskResult.isSuccess() && ObjectUtil.isNotEmpty(maskResult.getData())){
            ApiMaskEntity apiMask = null;
            try {
                apiMask = objectMapper.readValue(objectMapper.writeValueAsString(maskResult.getData()), ApiMaskEntity.class);
            } catch (JsonProcessingException e) {
            }
            rules = apiMask.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));
            ThreadUtil.getInstance().get().setStatus(DataConstant.EnableState.DISABLE.getKey());
            ThreadUtil.getInstance().get().setMsg(e.getMessage());
            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));
            ThreadUtil.getInstance().get().setStatus(DataConstant.EnableState.DISABLE.getKey());
            ThreadUtil.getInstance().get().setMsg(e.getMessage());
            throw new DataException("API调用数据脱敏出错");
        }
        pageResult.setPageNum(pageNum).setPageSize(pageSize);
        ThreadUtil.getInstance().get().setCallerSize(pageResult.getData().size());
        return pageResult;
    }
}
