package cn.fateverse.query.service.impl;

import cn.fateverse.query.entity.DataSourceManage;
import cn.fateverse.query.entity.DataSourceManageCount;
import cn.fateverse.query.mapper.TableMapper;
import cn.hutool.core.util.StrUtil;
import cn.fateverse.common.core.exception.CustomException;
import cn.fateverse.query.entity.dto.DataSourceManageDto;
import cn.fateverse.query.entity.vo.DataSourceManageVo;
import cn.fateverse.query.entity.query.DataSourceManageQuery;
import cn.fateverse.query.mapper.DataSourceManageMapper;
import cn.fateverse.query.service.DataSourceManageService;
import cn.fateverse.common.core.entity.Option;
import cn.fateverse.common.core.result.page.TableDataInfo;
import cn.fateverse.common.mybatis.utils.PageUtils;
import cn.fateverse.query.factory.DynamicDataSourceService;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 数据源管理 Controller
 *
 * @author clay
 * @date 2023-07-16
 */
@Slf4j
@Service
public class DataSourceManageServiceImpl implements DataSourceManageService {

    private final TableMapper tableMapper;

    private final DataSourceManageMapper dataSourceManageMapper;

    private final DynamicDataSourceService dynamicDataSourceService;

    public DataSourceManageServiceImpl(TableMapper tableMapper,
                                       DataSourceManageMapper dataSourceManageMapper,
                                       DynamicDataSourceService dynamicDataSourceService) {
        this.tableMapper = tableMapper;
        this.dataSourceManageMapper = dataSourceManageMapper;
        this.dynamicDataSourceService = dynamicDataSourceService;
    }

    @Override
    public DataSourceManageVo searchById(Long id) {
        DataSourceManage dataSourceManage = dataSourceManageMapper.selectById(id);
        DataSourceManageVo manageVo = DataSourceManageVo.toQueryDataSourceVo(dataSourceManage);
        manageVo.setHost(dataSourceManage.getHost());
        manageVo.setPort(dataSourceManage.getPort());
        manageVo.setParams(JSON.parseObject(dataSourceManage.getParams()));
        manageVo.setArgs(dataSourceManage.getArgs());
        return manageVo;
    }

    @Override
    public TableDataInfo<DataSourceManageVo> searchList(DataSourceManageQuery query) {
        PageUtils.startPage();
        List<DataSourceManage> list = dataSourceManageMapper.selectList(query);
        return PageUtils.convertDataTable(list, DataSourceManageVo::toQueryDataSourceVo);
    }

    @Override
    public List<Option> searchOptionList() {
        DataSourceManageQuery query = new DataSourceManageQuery();
        List<DataSourceManage> list = dataSourceManageMapper.selectList(query);
        return list.stream().map(item -> Option.builder()
                .value(item.getId())
                .label(item.getDsName())
                .build()).collect(Collectors.toList());
    }

    @Override
    public List<DataSourceManageVo> exportList(DataSourceManageQuery query) {
        List<DataSourceManage> list = dataSourceManageMapper.selectList(query);
        return list.stream().map(DataSourceManageVo::toQueryDataSourceVo)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public int save(DataSourceManageDto sourceManageDto) {
        DataSourceManage save = sourceManageDto.toQueryDataSource();
        checkConnect(save);
        return dataSourceManageMapper.insert(save);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public int edit(DataSourceManageDto sourceManageDto) {
        DataSourceManage edit = sourceManageDto.toQueryDataSource();
        if (StrUtil.isBlank(sourceManageDto.getPassword())) {
            DataSourceManage dataSourceManage = dataSourceManageMapper.selectById(sourceManageDto.getId());
            edit.setPassword(dataSourceManage.getPassword());
        }
        checkConnect(edit);
        dynamicDataSourceService.remove(sourceManageDto.getId());
        return dataSourceManageMapper.update(edit);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public int removeById(Long id) {
        dynamicDataSourceService.remove(id);
        return dataSourceManageMapper.deleteById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public int removeBatch(List<Long> idList) {
        List<DataSourceManageCount> dataSourceManageCountList = tableMapper.selectCountByDataSourceIds(idList);
        StringBuilder sb = new StringBuilder();
        boolean flag = false;
        for (DataSourceManageCount manageCount : dataSourceManageCountList) {
            if (manageCount.getCount() > 0) {
                sb.append("数据源'")
                        .append(manageCount.getDataSourceName())
                        .append("'存在")
                        .append(manageCount.getCount())
                        .append("张表,");
                flag = true;
            }
        }
        if (flag) {
            throw new CustomException(sb + "请先删除表!");
        }
        for (Long id : idList) {
            dynamicDataSourceService.remove(id);
        }
        return dataSourceManageMapper.deleteBatchByIdList(idList);
    }

    /**
     * 检查数据源的连接性
     *
     * @param dataSource 数据源
     */
    private void checkConnect(DataSourceManage dataSource) {
        if (!dynamicDataSourceService.checkDataSource(dataSource)) {
            throw new CustomException("数据源无法连接,请检查配置信息!");
        }
    }

}