package com.usoftchina.bi.server.service.dataSource;

import com.usoftchina.bi.core.base.*;
import com.usoftchina.bi.core.exception.MyException;
import com.usoftchina.bi.core.utils.GetTokenDataUtil;
import com.usoftchina.bi.server.dao.chart.ChartsConfigMapper;
import com.usoftchina.bi.server.dao.dataSource.DataConnectorMapper;
import com.usoftchina.bi.server.dao.user.UserMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageInfo;
import com.usoftchina.bi.server.model.bo.BaseToDataInfo;
import com.usoftchina.bi.server.model.bo.ColumnConfigAndSql;
import com.usoftchina.bi.server.model.bo.GroupUpdateId;
import com.usoftchina.bi.server.model.po.BaseConfig;
import com.usoftchina.bi.server.model.po.DataConnector;
import com.usoftchina.bi.server.model.po.DataConnectorList;
import com.usoftchina.bi.server.model.po.MessageLog;
import com.usoftchina.bi.server.model.vo.configVo.*;
import com.usoftchina.bi.server.model.vo.dataVo.ColumnValuesInfo;
import com.usoftchina.bi.server.model.vo.dataVo.DataSourceCopyInfo;
import com.usoftchina.bi.server.service.chart.GetChartsDataUtilService;
import com.usoftchina.bi.server.service.common.MessageLogService;
import com.usoftchina.bi.server.service.strategy.StrategysService;
import com.usoftchina.bi.server.service.chart.ChartsUtilService;
import com.usoftchina.bi.core.jdbc.DynamicDataSourceContextHolder;
import com.usoftchina.bi.server.utils.ScreenUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

@Service
public class DataConnectorService {

    @Autowired
    private DataConnectorMapper dataConnectorMapper;
    @Autowired
    ObjectMapper objectmapper;
    @Autowired
    ScreenUtil screenUtil;
    @Autowired
    StrategysService strategysService;
    @Autowired
    UserMapper userMapper;
    @Autowired
    ChartsConfigMapper chartsConfigMapper;
    @Autowired
    ChartsUtilService chartsUtilService;
    @Autowired
    GetChartsDataUtilService getChartsDataUtilService;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private MessageLogService messageLogService;

    private static final Logger logger = LoggerFactory.getLogger(DataConnectorService.class);

    /*
    保存数据源
     */
    public RepEntity setDataConnector(String token, DataConnectorInfo dataConnectorInfo) {

        Map<String, String> resultMap = GetTokenDataUtil.getTokenData(token);
        int id = Integer.parseInt(resultMap.get("id"));
        String userName = resultMap.get("name");

        if (dataConnectorInfo == null || "".equals(dataConnectorInfo)) {
            return new RepEntity(RepCode.Null);
        }
        DataConnector dataConnector = new DataConnector();
        BeanUtils.copyProperties(dataConnectorInfo, dataConnector);

        dataConnector.setTableName(dataConnector.getLoadObject());

        String columnConfig = null;
        String dataTag = null;

        try {
            columnConfig = objectmapper.writeValueAsString(dataConnectorInfo.getColumnConfig());
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        try {
            dataTag = objectmapper.writeValueAsString(dataConnectorInfo.getDataTag());
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        dataConnector.setColumnConfig(columnConfig);
        dataConnector.setDataTag(dataTag);
        if (dataConnector.getConnectorGroup() == 0) {
            dataConnector.setConnectorGroup(-1);
        }

        if (dataConnectorInfo.getNote() == null || "".equals(dataConnectorInfo)) {
            dataConnector.setNote("");
        }

        dataConnector.setCreateBy(userName);
        dataConnector.setCreateId(id);
        dataConnectorMapper.insertDataConnector(dataConnector);
        int dataId = dataConnector.getDataId();
        return new RepEntity(RepCode.success, dataId);
    }

    /**
     * 查看数据源列表
     *
     * @param token
     * @param testPage
     * @return
     */
//    @Cacheable(value = "dataConnector", key = "#testPage.pageNum")
    public RepEntity getListConnector(String token, TestPage testPage) {
        int id = BaseContextHolder.getUserId();
        String role = BaseContextHolder.getRole();
        List<DataConnectorList> listConnector = new ArrayList<>();
        if (RoleConstant.SUPER_ADMIN.getRole().equals(role)) {
            listConnector = dataConnectorMapper.getDataConnectorListWithoutLimit(id, testPage.enablePaging());
        }else {
            listConnector = dataConnectorMapper.getDataConnectorList(id, testPage.enablePaging());
        }
        List<DataConnectorList> listConnectors = new ArrayList<>();
        Iterator isList = listConnector.iterator();
        while (isList.hasNext()) {
            DataConnectorList dataConnectorList = (DataConnectorList) isList.next();
            BaseConfig baseConfig = dataConnectorList.getDbConfig();
            if (ObjectUtils.isEmpty(baseConfig)) {
                continue;
            }
            baseConfig.setPassWord("");
            dataConnectorList.setDbConfig(baseConfig);
            listConnectors.add(dataConnectorList);
        }
        PageInfo<DataConnectorList> pageInfo = new PageInfo<>(listConnectors);

        return new RepEntity(RepCode.success, pageInfo);
    }

    /*
    查看单个数据源配置
     */
//    @Cacheable(value = "singleDataConnector", key = "#body")
    public RepEntity getConnector(int id) {
        DataConnector dataConnector = dataConnectorMapper.getOneData(id);
        if (dataConnector == null) {
            return new RepEntity(RepCode.DataNonExistent);
        }
        return new RepEntity(RepCode.success, dataConnector);
    }

    /*
    更新数据源配置
     */
    //@CacheEvict(value = "singleDataConnector", key = "#body.dataId")
    public RepEntity updateData(DataConnectorInfo dataConnectorInfo) {

        if (dataConnectorInfo == null && "".equals(dataConnectorInfo)) {
            return new RepEntity(RepCode.Null);
        }
        DataConnector dataConnector = new DataConnector();
        BeanUtils.copyProperties(dataConnectorInfo, dataConnector);
        //获取表名
        dataConnector.setTableName(dataConnector.getLoadObject());
        List<ColumnRenameInfo> columnConfig = dataConnectorInfo.getColumnConfig();
        List<String> dataTag = dataConnectorInfo.getDataTag();


        String columnConfigJson = null;
        String dataTagJson = null;

        if (!("".equals(columnConfig)) && columnConfig != null) {
            try {
                columnConfigJson = objectmapper.writeValueAsString(columnConfig);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            dataConnector.setColumnConfig(columnConfigJson);
        }
        if (dataTag != null) {
            try {
                dataTagJson = objectmapper.writeValueAsString(dataTag);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            dataConnector.setDataTag(dataTagJson);
        }

        if (dataConnector.getConnectorGroup() == 0) {
            dataConnector.setConnectorGroup(-1);
        }

        dataConnectorMapper.updateData(dataConnector);
        return new RepEntity(RepCode.success);
    }

    /*
    转交数据源
     */
    public RepEntity changeOrder(ChangeOrderInfo changeOrderInfo) {
        int userId = BaseContextHolder.getUserId();
        String role = BaseContextHolder.getRole();
        String name = BaseContextHolder.getUserName();
        int createId = dataConnectorMapper.getCreateIdById(changeOrderInfo.getId());
        if (createId != userId && !RoleConstant.SUPER_ADMIN.getRole().equals(role)) {
            return new RepEntity(RepCode.NoAuthority);
        }
        dataConnectorMapper.updataOrder(name, changeOrderInfo.getUserId(), changeOrderInfo.getId());
        return new RepEntity(RepCode.success);
    }

    /*
    更新数据源分组
     */
    public RepEntity updateConfigGroup(String token, GroupUpdateId groupUpdateId) {
        String username = BaseContextHolder.getUserName();
        int id = groupUpdateId.getId();
        int groupId = groupUpdateId.getGroupId();
        GroupInfo groupInfo = dataConnectorMapper.getConnectorGroupById(groupId);
        String groupName = null;
        if (!ObjectUtils.isEmpty(groupInfo)) {
            groupName = groupInfo.getGroupName();
        }
        dataConnectorMapper.updateConfigGroup(id, groupId);
        String dataName = dataConnectorMapper.getOneData(id).getDataName();
        // 记录LOG
        MessageLog messageLog = new MessageLog(username, "更新数据源分组为( "+ groupName + ")", "更新成功", null, "数据源", dataName);
        messageLogService.customizeLog(messageLog);
        return new RepEntity(RepCode.success);
    }

    /*
    删除数据源
     */
    public RepEntity delDataConnector(String token, Long id) {
        String username = BaseContextHolder.getUserName();
        String dataName = dataConnectorMapper.getOneData(id.intValue()).getDataName();
        int count = dataConnectorMapper.countChartsById(id);
        if (count > 0) {
            throw new MyException(RepCode.CHARTS_USED_DATACONNECTOR);
        }
        dataConnectorMapper.deleteData(id);
        // 记录LOG
        messageLogService.delete("数据源", dataName, username, null);
        return new RepEntity(RepCode.success);
    }

    /*
    创建数据源分组
     */
    public RepEntity setDataConnectorGroup(String token, GroupInfo groupInfo) {
        String username = BaseContextHolder.getUserName();
        if (groupInfo == null || "".equals(groupInfo)) {
            return new RepEntity(RepCode.Null);
        }
        dataConnectorMapper.setConnectorGroup(groupInfo);
        int id = groupInfo.getId();
        // 记录LOG
        messageLogService.save("数据源分组", groupInfo.getGroupName(), username, "创建数据源分组");
        return new RepEntity(RepCode.success, id);
    }

    /**
     * 批量更新数据源分组
     * @param groupInfoList
     * @return
     */
    @Transactional
    public RepEntity saveConnectorGroups(String token, List<GroupInfo> groupInfoList) {
        String username = BaseContextHolder.getUserName();
        List<GroupInfo> addGroupInfoList = new ArrayList<>();
        List<GroupInfo> deleteGroupInfoList = new ArrayList<>();
        List<GroupInfo> updateGroupInfoList = new ArrayList<>();
        groupInfoList.forEach(groupInfo -> {
            if ("add".equals(groupInfo.getOperate())) {
                addGroupInfoList.add(groupInfo);
            }else if ("delete".equals(groupInfo.getOperate())) {
                deleteGroupInfoList.add(groupInfo);
            }else if ("update".equals(groupInfo.getOperate())) {
                updateGroupInfoList.add(groupInfo);
            }
        });
        if (addGroupInfoList.size() > 0) {
            messageLogService.save("数据源分组", null, username, "批量新增数据源分组");
            dataConnectorMapper.batchInsertDataConnector(addGroupInfoList);
        }
        if (updateGroupInfoList.size() > 0) {
            messageLogService.save("数据源分组", null, username, "批量更新数据源分组");
            dataConnectorMapper.batchUpdateDataConnector(updateGroupInfoList);
        }
        if (deleteGroupInfoList.size() > 0) {
            messageLogService.save("数据源分组", null, username, "批量删除数据源分组");
            dataConnectorMapper.batchUpdateGroupIdToDefault(deleteGroupInfoList);
            dataConnectorMapper.batchDeleteDataConnector(deleteGroupInfoList);
        }
        return new RepEntity(RepCode.success);
    }

    /*
    更新数据源分组
     */
    public RepEntity updataDataConnectorGroup(String token, GroupInfo groupInfo) {
        dataConnectorMapper.updataConnectorGroup(groupInfo);
        String username = BaseContextHolder.getUserName();
        messageLogService.update("数据源分组", groupInfo.getGroupName(), username, "更新分组");
        return new RepEntity(RepCode.success);
    }

    /*
   批量更新数据源分组
    */
    public RepEntity updataConnectorGroups(List<GroupInfo> groupInfoList) {
        Iterator isList = groupInfoList.iterator();
        GroupInfo groupInfo = new GroupInfo();
        while (isList.hasNext()) {
            groupInfo = (GroupInfo) isList.next();
            dataConnectorMapper.updataConnectorGroup(groupInfo);
        }

        return new RepEntity(RepCode.success);
    }

    /*
    删除数据源分组
     */
    public RepEntity delDataConnectorGroup(String token, Long id) {
        String username = BaseContextHolder.getUserName();
        List<String> groupName = dataConnectorMapper.getFatherId(id.intValue());
        if (groupName.size() != 0) {
            return new RepEntity(RepCode.hasGroupUsing);
        }
        List<String> chartName = dataConnectorMapper.getConName(id.intValue());
        if (chartName.size() != 0) {
            return new RepEntity(RepCode.hasConUsing);
        }
        String dataName = dataConnectorMapper.getOneData(id.intValue()).getDataName();
        dataConnectorMapper.delConnectorGroup(id);
        // 更新分组字段值
        dataConnectorMapper.updateGroupIdToDefault(id);
        messageLogService.delete("数据源分组", dataName, username, "删除数据源分组");
        return new RepEntity(RepCode.success);
    }

    /*
    查询数据源分组列表
     */
    public RepEntity getConnectorGroup() {
        return new RepEntity(RepCode.success, dataConnectorMapper.getConnectorGroup());
    }

    /*
    查询数据源数据
     */
    public RepEntity getConnectorData(String token, BaseToDataInfo baseToDataInfo) {

        int dataId = baseToDataInfo.getId();
        int baseId = getChartsDataUtilService.getBaseIdByConnect(dataId);
        logger.info("切换数据库:{}", baseId);

        int id = BaseContextHolder.getUserId();
        int createId = dataConnectorMapper.getCreateIdById(dataId);
        ColumnValuesInfo columnValuesInfo = new ColumnValuesInfo();
        ColumnConfigAndSql columnConfigAndSql = chartsConfigMapper.getConfigAndSql(dataId);
        String sql = columnConfigAndSql.getSql();
        String columnConfig = columnConfigAndSql.getColumnConfig();
        columnValuesInfo.setColumnConfig(columnConfig);
        if (RoleConstant.SUPER_ADMIN.getRole().equals(BaseContextHolder.getRole())) {
            id = createId;
        }
        String sqls = chartsUtilService.columnNameUtil(id, dataId, sql, true, 0, createId);

        try {
            if (!DynamicDataSourceContextHolder.isContainsDataSource(baseId)) {
                logger.info("数据源:{} 不存在, 使用默认的数据源", baseId);
            } else {
                logger.info("使用数据源：", baseId);
                DynamicDataSourceContextHolder.setDataSourceType(baseId);
            }
            List<Map<String, Object>> val = new ArrayList<>();
            if (id == createId) {
                val = dataConnectorMapper.getValues(sql, baseToDataInfo.getTestPage().enablePaging());
            } else {
                if ("".equals(sqls)) {
                    return new RepEntity(RepCode.NoAuthority);
                }
                val = dataConnectorMapper.getValues(sql, baseToDataInfo.getTestPage().enablePaging());
            }

            PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(val);
            columnValuesInfo.setValues(pageInfo);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            throw new MyException(e.getCause().getMessage());
        } finally {
            logger.info("关闭数据源");
            DynamicDataSourceContextHolder.clearDataSourceType();
        }
        return new RepEntity(RepCode.success, columnValuesInfo);
    }

    /**
     * 数据源复制
     * @param token
     * @param dataSourceCopyInfo
     * @return
     */
    public RepEntity<Integer> copyDataSource(String token, DataSourceCopyInfo dataSourceCopyInfo){
        Map<String,String> userData = GetTokenDataUtil.getTokenData(token);
        int userId = Integer.valueOf(userData.get("id"));
        String userName = userData.get("name");

        int dataSourceId = dataSourceCopyInfo.getDataSourceId(),
            dataConnectionId = dataSourceCopyInfo.getDataConnectionId();
        DataConnector dataConnector = dataConnectorMapper.getOneData(dataSourceId);
        String loadObject = dataConnector.getLoadObject();
        //校验SQL语句是否可正确在目标数据库执行
        enableCopy(loadObject, dataConnectionId);
        //复制数据源
        dataConnector.setDataName(dataConnector.getDataName() + dataSourceCopyInfo.getLastName());
        dataConnector.setCreateBy(userName);
        dataConnector.setCreateId(userId);
        dataConnector.setDbConId(String.valueOf(dataConnectionId));
        dataConnector.setTableName(dataConnector.getLoadObject());
        dataConnectorMapper.insertDataConnector(dataConnector);
        int dataId = dataConnector.getDataId();
        return new RepEntity(RepCode.success, dataId);
    }

    /**
     * 校验SQL在新数据连接中是否可以正确执行
     * @param loadObject
     * @param dataConnectionId
     */
    public void enableCopy(String loadObject, int dataConnectionId){
        DynamicDataSourceContextHolder.setDataSourceType(dataConnectionId);
        if (!loadObject.toUpperCase().startsWith("SELECT")) {
            loadObject = "SELECT * FROM " + loadObject;
        }
        try {
            jdbcTemplate.queryForRowSet(loadObject);
        } catch (DataAccessException e) {
            throw new MyException(e.getCause().getMessage());
        } finally {
            DynamicDataSourceContextHolder.clearDataSourceType();
        }

    }

}
