package com.ruoyi.dxp.service.impl;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.dxp.constant.DxpConstants;
import com.ruoyi.dxp.constant.DxpRedisKeyConstants;
import com.ruoyi.dxp.domain.*;
import com.ruoyi.dxp.dto.database.DatabaseUtilsColnInfoDto;
import com.ruoyi.dxp.dto.database.DatabaseUtilsCreateTableParam;
import com.ruoyi.dxp.dto.redis.*;
import com.ruoyi.dxp.mapper.*;
import com.ruoyi.dxp.service.ITableService;
import com.ruoyi.dxp.utils.DatabaseUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.dxp.service.IServiceCacheService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 服务缓存Service业务层处理
 * 
 * @author jy
 * @date 2023-01-04
 */
@Service
public class ServiceCacheServiceImpl implements IServiceCacheService 
{
    @Autowired
    private ServiceCacheMapper serviceCacheMapper;

    @Autowired
    private ServiceShareMapper serviceShareMapper;

    @Autowired
    private DatabaseMapper databaseMapper;

    @Autowired
    private TableMapper tableMapper;

    @Autowired
    private ServiceItemMapper serviceItemMapper;

    @Autowired
    private TableColumnMapper tableColumnMapper;

    @Autowired
    private ITableService tableService;

    @Autowired
    private RedisCache redisCache;

    /**
     * 查询服务缓存
     * 
     * @param id 服务缓存主键
     * @return 服务缓存
     */
    @Override
    public ServiceCache selectServiceCacheById(Long id)
    {
        return serviceCacheMapper.selectServiceCacheById(id);
    }

    /**
     * 查询服务缓存列表
     * 
     * @param serviceCache 服务缓存
     * @return 服务缓存
     */
    @Override
    public List<ServiceCache> selectServiceCacheList(ServiceCache serviceCache)
    {
        return serviceCacheMapper.selectServiceCacheList(serviceCache);
    }

    /**
     * 新增服务缓存
     * 
     * @param serviceCache 服务缓存
     * @return 结果
     */
    @Override
    public int insertServiceCache(ServiceCache serviceCache)
    {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        serviceCache.setCreateBy(loginUser.getUsername());
        serviceCache.setCreateTime(DateUtils.getNowDate());
        return serviceCacheMapper.insertServiceCache(serviceCache);
    }

    /**
     * 修改服务缓存
     * 
     * @param serviceCache 服务缓存
     * @return 结果
     */
    @Override
    public int updateServiceCache(ServiceCache serviceCache)
    {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        serviceCache.setUpdateBy(loginUser.getUsername());
        serviceCache.setUpdateTime(DateUtils.getNowDate());
        return serviceCacheMapper.updateServiceCache(serviceCache);
    }

    /**
     * 批量删除服务缓存
     * 
     * @param ids 需要删除的服务缓存主键
     * @return 结果
     */
    @Override
    public int deleteServiceCacheByIds(Long[] ids)
    {
        return serviceCacheMapper.deleteServiceCacheByIds(ids);
    }

    /**
     * 删除服务缓存信息
     * 
     * @param id 服务缓存主键
     * @return 结果
     */
    @Override
    public int deleteServiceCacheById(Long id)
    {
        ServiceCache serviceCache = serviceCacheMapper.selectServiceCacheById(id);
        if (serviceCache == null) {
            return 0;
        }

        // 删除本地数据表
        tableService.deleteTableById(serviceCache.getTableId());

        // 删除远程数据表
        DatabaseUtils.deleteTable(serviceCache.getDatabaseId(), serviceCache.getTableName());

        return serviceCacheMapper.deleteServiceCacheById(id);
    }

    /**
     * 保存
     * @param serviceCache 保存对象
     * @return 保存结果
     */
    @Override
    @Transactional
    public AjaxResult save(ServiceCache serviceCache) {
        Boolean isAdd = serviceCache.getId() == null;
        if (serviceCache.getServiceId() == null) {
            return AjaxResult.error("共享服务不能为空");
        }

        ServiceShare serviceShare = serviceShareMapper.selectServiceShareById(serviceCache.getServiceId());
        if (serviceShare == null || !serviceShare.getStatus().equals(DxpConstants.STATUS_VALID)) {
            return AjaxResult.error("共享服务不存在或非正常状态");
        }

        if (serviceCache.getDatabaseId() == null) {
            return AjaxResult.error("数据源不能为空");
        }

        Database database = databaseMapper.selectDatabaseById(serviceCache.getDatabaseId());
        if (database == null) {
            return AjaxResult.error("数据源不存在");
        }

        if (StringUtils.isEmpty(serviceCache.getTableName())) {
            return AjaxResult.error("缓存表名不能为空");
        }

        if (isAdd) {
            Table req = new Table();
            req.setDatabaseId(serviceCache.getDatabaseId());
            req.setTableName(serviceCache.getTableName());
            List<Table> tableList = tableMapper.selectTableList(req);
            if (tableList != null && tableList.size() > 0) {
                return AjaxResult.error("当前表已经在选中的数据源中存在");
            }
        }

        if (StringUtils.isEmpty(serviceCache.getCacheCycleUnit())) {
            return AjaxResult.error("周期单位不能为空");
        }

        if (StringUtils.isEmpty(serviceCache.getCacheCycleValue())) {
            return AjaxResult.error("周期值不能为空");
        }

        if (StringUtils.isEmpty(serviceCache.getMode())) {
            return AjaxResult.error("同步模式不能为空");
        }

        if (serviceCache.getMode().equals("add") && serviceCache.getMode().equals("full")) {
            return AjaxResult.error("同步模式错误");
        }

        if (serviceCache.getMode().equals("add") && StringUtils.isEmpty(serviceCache.getAddField())) {
            return AjaxResult.error("增量字段不能为空");
        }

        LoginUser loginUser = SecurityUtils.getLoginUser();

        // 新建时处理远程表和表结构
        if (isAdd) {
            // 读取服务出参
            ServiceItem req = new ServiceItem();
            req.setServiceId(serviceCache.getServiceId());
            req.setServiceType(DxpConstants.DATA_TYPE_SHARE);
            req.setParamType(DxpConstants.PARAM_TYPE_OUT);
            List<ServiceItem> serviceItems = serviceItemMapper.selectServiceItemList(req);

            List<ServiceItem> collect = serviceItems.stream().filter(p -> StringUtils.isEmpty(p.getMapColumnName())).collect(Collectors.toList());
            if (collect != null && collect.size() > 0) {
                return AjaxResult.error("所有出参都必须配置映射字段才能进行服务缓存");
            }

            // 远程建表
            List<DatabaseUtilsColnInfoDto> columns = new ArrayList<>();
            for (ServiceItem serviceItem : serviceItems) {
                DatabaseUtilsColnInfoDto col = new DatabaseUtilsColnInfoDto();
                col.setColName(serviceItem.getMapColumnName());
                if (serviceItem.getMapColumnName().equals("id")) {
                    col.setDataType("bigint");
                    col.setDataLength(20);
                    col.setIsIncrement(1);
                    col.setIsPk(1);
                    col.setIsRequired(1);
                } else {
                    col.setDataType("varchar");
                    col.setDataLength(400);
                    col.setIsIncrement(0);
                    col.setIsPk(0);
                    col.setIsRequired(0);
                }

                columns.add(col);
            }

            DatabaseUtilsCreateTableParam createTableParam = new DatabaseUtilsCreateTableParam();
            createTableParam.setColumns(columns);
            createTableParam.setConnection(database.getConnectionString());
            createTableParam.setDbName(database.getDatabaseName());
            createTableParam.setId(database.getId());
            createTableParam.setTbName(serviceCache.getTableName());
            createTableParam.setDbType(database.getDatabaseType());
            R<String> createResult = DatabaseUtils.createTable(createTableParam);
            if (createResult.getCode() != HttpStatus.SUCCESS) {
                return AjaxResult.error("远程建表失败：" + createResult.getMsg());
            }

            // 本地保存表数据
            Table table = new Table();
            table.setDatabaseId(serviceCache.getDatabaseId());
            table.setTableName(serviceCache.getTableName());
            table.setTableComment("服务数据缓存");
            table.setCreateBy(loginUser.getUsername());
            table.setCreateTime(DateUtils.getNowDate());
            tableMapper.insertTable(table);

            // 本地保存表列数据
            R<List<TableColumn>> columnListResult = DatabaseUtils.getColumnList(database.getId(), table.getTableName());
            if (columnListResult.getCode() == HttpStatus.SUCCESS) {
                // 保存列
                List<TableColumn> tableColumns = columnListResult.getData();
                if (tableColumns != null && tableColumns.size() > 0) {
                    for (TableColumn column : tableColumns) {
                        column.setDatabaseId(database.getId());
                        column.setTableId(table.getId());
                        column.setCreateTime(DateUtils.getNowDate());
                        column.setCreateBy(loginUser.getUsername());
                        this.tableColumnMapper.insertTableColumn(column);
                    }
                }
            }

            serviceCache.setTableId(table.getId());
        }

        ServiceCache saveServiceCache = new ServiceCache();
        BeanUtils.copyProperties(serviceCache, saveServiceCache);
        saveServiceCache.setServiceName(serviceShare.getServiceName());
        saveServiceCache.setDatabaseName(database.getDatabaseName());
        saveServiceCache.setStatus(DxpConstants.STATUS_VALID);

        if (isAdd) {
            saveServiceCache.setCreateBy(loginUser.getUsername());
            saveServiceCache.setCreateTime(DateUtils.getNowDate());
            serviceCacheMapper.insertServiceCache(saveServiceCache);
        } else {
            saveServiceCache.setUpdateBy(loginUser.getUsername());
            saveServiceCache.setUpdateTime(DateUtils.getNowDate());
            serviceCacheMapper.updateServiceCache(saveServiceCache);
        }

        // 写入redis
        this.writeToRedis();

        return AjaxResult.success(saveServiceCache.getId());
    }

    /**
     * 配置写入redis
     */
    public void writeToRedis() {
        // 查询所有配置
        ServiceCache req = new ServiceCache();
        req.setStatus(DxpConstants.STATUS_VALID);
        List<ServiceCache> serviceCaches = serviceCacheMapper.selectServiceCacheList(req);
        List<RedisServiceCacheDto> redisDatabaseDtos = new ArrayList<>();
        if (serviceCaches != null && serviceCaches.size() > 0) {
            for (ServiceCache serviceCache : serviceCaches) {
                RedisServiceCacheDto redisServiceCacheDto = new RedisServiceCacheDto();
                redisServiceCacheDto.setId(serviceCache.getId());
                redisServiceCacheDto.setMode(serviceCache.getMode());
                redisServiceCacheDto.setAddField(serviceCache.getAddField());
                redisServiceCacheDto.setPageField(serviceCache.getPageField());
                redisServiceCacheDto.setPageSizeField(serviceCache.getPageSizeField());
                redisServiceCacheDto.setSearchField(serviceCache.getSearchField());

                // 基础
                RedisServiceCacheServiceConfigDto redisServiceCacheServiceConfigDto = new RedisServiceCacheServiceConfigDto();
                ServiceShare serviceShare = serviceShareMapper.selectServiceShareById(serviceCache.getServiceId());
                if (serviceShare == null) {
                    continue;
                }

                redisServiceCacheServiceConfigDto.setServiceUrl(serviceShare.getServiceUrl());
                redisServiceCacheServiceConfigDto.setAuthWay(serviceShare.getAuthWay());
                redisServiceCacheServiceConfigDto.setParamForm(serviceShare.getParamForm());
                redisServiceCacheServiceConfigDto.setRequestMethod(serviceShare.getRequestMethod());
                redisServiceCacheServiceConfigDto.setRequestParam(serviceCache.getRequestParam());

                // 映射关系
                ServiceItem iReq = new ServiceItem();
                iReq.setParamType(DxpConstants.PARAM_TYPE_OUT);
                iReq.setServiceType(DxpConstants.DATA_TYPE_SHARE);
                iReq.setServiceId(serviceCache.getServiceId());
                List<ServiceItem> serviceItems = serviceItemMapper.selectServiceItemList(iReq);
                if (serviceItems == null || serviceItems.size() == 0) {
                    continue;
                }

                List<RedisServiceCacheColumnMap> maps = new ArrayList<>();
                for (ServiceItem serviceItem : serviceItems) {
                    RedisServiceCacheColumnMap redisServiceCacheColumnMap = new RedisServiceCacheColumnMap();
                    redisServiceCacheColumnMap.setColumnName(serviceItem.getMapColumnName());
                    redisServiceCacheColumnMap.setFieldName(serviceItem.getParamName());
                    maps.add(redisServiceCacheColumnMap);
                }
                redisServiceCacheServiceConfigDto.setColumnMap(maps);
                redisServiceCacheDto.setServiceConfig(redisServiceCacheServiceConfigDto);

                // 数据源配置
                RedisServiceCacheDbConfigDto redisServiceCacheDbConfigDto = new RedisServiceCacheDbConfigDto();
                Database database = databaseMapper.selectDatabaseById(serviceCache.getDatabaseId());
                if (database == null) {
                    continue;
                }

                redisServiceCacheDbConfigDto.setDbId(database.getId());
                redisServiceCacheDbConfigDto.setType(database.getDatabaseType());
                redisServiceCacheDbConfigDto.setConnectionString(database.getConnectionString());
                redisServiceCacheDbConfigDto.setTbName(serviceCache.getTableName());
                redisServiceCacheDto.setDbConfig(redisServiceCacheDbConfigDto);

                // 服务配置
                RedisServiceCacheCycleDto redisServiceCacheCycleDto = new RedisServiceCacheCycleDto();
                redisServiceCacheCycleDto.setUnit(serviceCache.getCacheCycleUnit());
                redisServiceCacheCycleDto.setValue(serviceCache.getCacheCycleValue());
                redisServiceCacheDto.setCacheCycle(redisServiceCacheCycleDto);

                redisDatabaseDtos.add(redisServiceCacheDto);
            }

            redisCache.deleteObject(DxpRedisKeyConstants.SERVICE_CANCHE);
            redisCache.setCacheList(DxpRedisKeyConstants.SERVICE_CANCHE, redisDatabaseDtos);
        }
    }
}
