package controller

import (
	"encoding/json"
	"fmt"

	"be.ems/src/framework/constants"
	"be.ems/src/framework/database/redis"
	"be.ems/src/framework/i18n"
	"be.ems/src/framework/reqctx"
	"be.ems/src/framework/resp"
	"be.ems/src/modules/monitor/model"

	"github.com/gin-gonic/gin"
)

// 实例化控制层 SysCacheController 结构体
var NewSysCache = &SysCacheController{}

// 缓存监控信息
//
// PATH /monitor/cache
type SysCacheController struct{}

// Redis信息
//
// GET /
//
//	@Tags			monitor/cache
//	@Accept			json
//	@Produce		json
//	@Success		200	{object}	object	"Response Results"
//	@Security		TokenAuth
//	@Summary		Cache Service Information
//	@Description	Cache Service Information
//	@Router			/monitor/cache [get]
func (s *SysCacheController) Info(c *gin.Context) {
	c.JSON(200, resp.OkData(map[string]any{
		"info":         redis.Info(""),
		"dbSize":       redis.KeySize(""),
		"commandStats": redis.CommandStats(""),
	}))
}

// Names 缓存名称列表
//
// GET /names
func (s SysCacheController) Names(c *gin.Context) {
	language := reqctx.AcceptLanguage(c)
	caches := []model.SysCache{
		model.NewNames(i18n.TKey(language, "cache.name.token"), constants.CACHE_TOKEN_DEVICE),
		model.NewNames(i18n.TKey(language, "cache.name.sys_config"), constants.CACHE_SYS_CONFIG),
		model.NewNames(i18n.TKey(language, "cache.name.sys_dict"), constants.CACHE_SYS_DICT),
		model.NewNames(i18n.TKey(language, "cache.name.captcha_codes"), constants.CACHE_CAPTCHA_CODE),
		model.NewNames(i18n.TKey(language, "cache.name.repeat_submit"), constants.CACHE_REPEAT_SUBMIT),
		model.NewNames(i18n.TKey(language, "cache.name.rate_limit"), constants.CACHE_RATE_LIMIT),
		model.NewNames(i18n.TKey(language, "cache.name.pwd_err_cnt"), constants.CACHE_PWD_ERR_COUNT),
		model.NewNames(i18n.TKey(language, "cache.name.oauth2_codes"), constants.CACHE_OAUTH2_CODE),
		model.NewNames(i18n.TKey(language, "cache.name.oauth2_devices"), constants.CACHE_OAUTH2_DEVICE),
		model.NewNames(i18n.TKey(language, "cache.name.i18n"), constants.CACHE_I18N),
		model.NewNames(i18n.TKey(language, "cache.name.ne_info"), constants.CACHE_NE_INFO),
		model.NewNames(i18n.TKey(language, "cache.name.ne_data"), constants.CACHE_NE_DATA),
	}
	c.JSON(200, resp.OkData(caches))
}

// Keys 缓存名称下键名列表
//
// GET /keys?cacheName=xxx
func (s SysCacheController) Keys(c *gin.Context) {
	var query struct {
		CacheName string `form:"cacheName" binding:"required"` // 键名列表中得到的缓存名称
	}
	if err := c.ShouldBindQuery(&query); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}

	caches := []model.SysCache{}
	cacheKeys, _ := redis.GetKeys("", query.CacheName+":*")
	for _, key := range cacheKeys {
		caches = append(caches, model.NewKeys(query.CacheName, key))
	}

	c.JSON(200, resp.OkData(caches))
}

// Value 缓存内容信息
//
// GET /value?cacheName=xxx&cacheKey=xxx
func (s SysCacheController) Value(c *gin.Context) {
	var query struct {
		CacheName string `form:"cacheName" binding:"required"` // 键名列表中得到的缓存名称
		CacheKey  string `form:"cacheKey" binding:"required"`  // 键名列表中得到的缓存键名
	}
	if err := c.ShouldBindQuery(&query); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}

	key := query.CacheName + ":" + query.CacheKey

	var cacheValue string
	var err error

	if constants.CACHE_I18N == query.CacheName {
		// i18n 多语言的hash对象
		m, err := redis.GetHashBatch("", []string{key})
		if err != nil {
			c.JSON(200, resp.ErrMsg(err.Error()))
			return
		}
		b, err := json.Marshal(m[key])
		if err != nil {
			c.JSON(200, resp.ErrMsg(err.Error()))
			return
		}
		cacheValue = string(b)
	} else {
		// 其他的字符串对象
		cacheValue, err = redis.Get("", query.CacheName+":"+query.CacheKey)
		if err != nil {
			c.JSON(200, resp.ErrMsg(err.Error()))
			return
		}
	}

	sysCache := model.NewValue(query.CacheName, query.CacheKey, cacheValue)
	c.JSON(200, resp.OkData(sysCache))
}

// CleanNames 缓存名称列表安全删除
//
// DELETE /names
func (s SysCacheController) CleanNames(c *gin.Context) {
	language := reqctx.AcceptLanguage(c)
	caches := []model.SysCache{
		model.NewNames(i18n.TKey(language, "cache.name.sys_config"), constants.CACHE_SYS_CONFIG),
		model.NewNames(i18n.TKey(language, "cache.name.sys_dict"), constants.CACHE_SYS_DICT),
		model.NewNames(i18n.TKey(language, "cache.name.repeat_submit"), constants.CACHE_REPEAT_SUBMIT),
		model.NewNames(i18n.TKey(language, "cache.name.rate_limit"), constants.CACHE_RATE_LIMIT),
		model.NewNames(i18n.TKey(language, "cache.name.pwd_err_cnt"), constants.CACHE_PWD_ERR_COUNT),
		model.NewNames(i18n.TKey(language, "cache.name.i18n"), constants.CACHE_I18N),
		model.NewNames(i18n.TKey(language, "cache.name.ne_info"), constants.CACHE_NE_INFO),
		model.NewNames(i18n.TKey(language, "cache.name.ne_data"), constants.CACHE_NE_DATA),
	}
	for _, v := range caches {
		cacheKeys, err := redis.GetKeys("", v.CacheName+":*")
		if err != nil {
			continue
		}
		_ = redis.DelKeys("", cacheKeys)
	}
	c.JSON(200, resp.Ok(nil))
}

// CleanKeys 缓存名称下键名删除
//
// DELETE /keys?cacheName=xxx
func (s SysCacheController) CleanKeys(c *gin.Context) {
	var query struct {
		CacheName string `form:"cacheName" binding:"required"` // 键名列表中得到的缓存名称
	}
	if err := c.ShouldBindQuery(&query); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}
	if constants.CACHE_TOKEN_DEVICE == query.CacheName {
		c.JSON(200, resp.ErrMsg("Cannot delete user information cache"))
		return
	}

	cacheKeys, err := redis.GetKeys("", query.CacheName+":*")
	if err != nil {
		c.JSON(200, resp.ErrMsg(err.Error()))
		return
	}

	if err = redis.DelKeys("", cacheKeys); err != nil {
		c.JSON(200, resp.ErrMsg(err.Error()))
		return
	}
	c.JSON(200, resp.Ok(nil))
}

// CleanValue 缓存内容删除
//
// DELETE /value?cacheName=xxx&cacheKey=xxx
func (s SysCacheController) CleanValue(c *gin.Context) {
	var query struct {
		CacheName string `form:"cacheName" binding:"required"` // 键名列表中得到的缓存名称
		CacheKey  string `form:"cacheKey" binding:"required"`  // 键名列表中得到的缓存键名
	}
	if err := c.ShouldBindQuery(&query); err != nil {
		errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
		c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
		return
	}

	if err := redis.Del("", query.CacheName+":"+query.CacheKey); err != nil {
		c.JSON(200, resp.ErrMsg(err.Error()))
		return
	}
	c.JSON(200, resp.Ok(nil))
}
