package com.ruoyi.web.controller.monitor;

import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.paginate.Page;
import com.ruoyi.common.constants.CacheConstant;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.RedisUtil;
import com.ruoyi.common.web.controller.BaseController;
import com.ruoyi.common.web.domain.PageData;
import com.ruoyi.common.web.domain.entity.Cache;
import com.ruoyi.framework.annotation.RyLog;
import org.noear.solon.annotation.*;
import org.noear.solon.auth.annotation.AuthPermissions;
import org.noear.solon.core.handle.Result;
import org.redisson.api.RKeys;
import org.redisson.api.RScript;
import org.redisson.api.RedissonClient;
import org.redisson.api.RType;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 缓存监控
 * @author ruoyi
 */
@Controller
@Mapping("monitor/cache")
public class CacheController extends BaseController {

    @Inject
    RedissonClient redissonClient;

    @Inject
    RedisUtil redisUtil;

    /**
     * 查询缓存列表
     */
    @AuthPermissions("monitor:cache:list")
    @Get
    @Mapping("list")
    public PageData<Cache> list(Page<Cache> page, Cache cache) {
        List<Cache> cacheList = getList(cache);
        // 分页
        List<Cache> list = cacheList.stream()
                .skip((page.getPageNumber() - 1) * page.getPageSize())
                .limit(page.getPageSize())
                .collect(Collectors.toList());
        return getPageData(list).total(cacheList.size());
    }

    /**
     * 删除缓存
     */
    @RyLog(title = "缓存监控", businessType = BusinessType.DELETE)
    @AuthPermissions("monitor:cache:remove")
    @Delete
    @Mapping
    public Result<Void> delete(Cache cache) {
        RType type = RType.valueOf(cache.getName());
        boolean b = false;
        switch (type) {
            case OBJECT:
                b = redisUtil.deleteCacheObject(cache.getKey());
                break;
            case LIST:
                b = redisUtil.deleteCacheList(cache.getKey());
                break;
            case MAP:
                b = redisUtil.deleteCacheMap(cache.getKey());
                break;
            case SET:
                b = redisUtil.deleteCacheSet(cache.getKey());
                break;
            case ZSET:
                b = redisUtil.deleteCacheZSet(cache.getKey());
                break;
            default:
                break;
        }
        return toResult(b);
    }

    /**
     * 查询缓存信息
     * @return
     */
    @AuthPermissions("monitor:cache:query")
    @Get
    @Mapping("info")
    public Result<Map<String, String>> info() {
        RScript script = redissonClient.getScript();
        String info = script.eval(RScript.Mode.READ_ONLY, "return redis.call('info');", RScript.ReturnType.STATUS);
        Map<String, String> map = new HashMap<>();
        if(StrUtil.isNotEmpty(info)) {
            List<String> split = StrUtil.split(info, "\r\n");
            for (String s : split) {
                if(StrUtil.isNotEmpty(s) && StrUtil.contains(s, ":")) {
                    String[] strings = StrUtil.splitToArray(s, ":");
                    map.put(strings[0], strings[1]);
                }
            }
        }
        return Result.succeed(map);
    }

    private List<Cache> getList(Cache cache) {
        RKeys keys = redissonClient.getKeys();
        List<Cache> cacheList = new ArrayList<>();
        for (String key : keys.getKeys()) {
            Cache cc = new Cache();
            RType type = keys.getType(key);
            cc.setType(type.getValue());
            cc.setName(type.name());
            cc.setKey(key);
            getValue(cc, key, type);
            getDesc(cc, key);
            cacheList.add(cc);
        }
        // 根据查询条件检索
        return cacheList.stream()
                .filter(cc -> StrUtil.isEmpty(cache.getKey()) || cc.getKey().contains(cache.getKey()))
                .collect(Collectors.toList());
    }

    private void getValue(Cache cache, String key, RType type) {
        switch (type) {
            case OBJECT:
                cache.setValue(Collections.singletonList(redisUtil.getCacheObject(key)));
                break;
            case LIST:
                cache.setValue(redisUtil.getCacheList(key));
                break;
            case MAP:
                cache.setValue(redisUtil.getCacheMap(key));
                break;
            case SET:
                cache.setValue(redisUtil.getCacheSet(key));
                break;
            case ZSET:
                cache.setValue(redisUtil.getCacheZSetRange(key, 1, -1));
                break;
            default:
                break;
        }
    }

    private void getDesc(Cache cache, String key) {
        if(key.startsWith(CacheConstant.CAPTCHA_CODE_KEY)) {
            cache.setDescription("验证码");
        } else if(key.startsWith(CacheConstant.LOGIN_ERROR_KEY)) {
            cache.setDescription("登录失败");
        } else if(key.startsWith(CacheConstant.SYS_DICT_KEY)) {
            cache.setDescription("数据字典");
        } else if(key.startsWith(CacheConstant.SYS_CONFIG_KEY)) {
            cache.setDescription("系统参数");
        } else if(key.startsWith(CacheConstant.RATE_LIMIT_KEY)) {
            cache.setDescription("限流");
        }
    }

}
