package log

import (
	"context"
	"errors"
	"github.com/go-redis/redis/v8"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"log-server/global"
	"log-server/model/log"
	"log-server/model/log/request"
	"log-server/model/log/response"
	"log-server/service/cache"
	"strconv"
	"time"
)

type ServiceLogCoding struct {
	cache cache.Cache
}

var codeListCacheKey = "log:code"

func (s *ServiceLogCoding) CreateCoding(requestCoding request.CodingLogRequest) (err error) {
	if !errors.Is(global.GVA_DB.Where("coding = ?", requestCoding.Coding).First(&log.CodingLog{}).Error, gorm.ErrRecordNotFound) {
		return errors.New("存在相同coding")
	}
	coding := new(log.CodingLog)
	if requestCoding.ParentId == 0 {
		coding.Level = 1
	} else {
		logCoding := new(log.CodingLog)
		err = global.GVA_DB.Where("id = ?", requestCoding.ParentId).First(logCoding).Error
		if err != nil {
			return err
		}
		if logCoding.Id == 0 {
			return errors.New("没有找到父节点")
		}
		if logCoding.Level >= 3 {
			return errors.New("该节点不能添加下级")
		}
		coding.Level = logCoding.Level + 1
	}
	coding.ParentId = requestCoding.ParentId
	coding.Coding = requestCoding.Coding
	coding.Describe = requestCoding.Describe
	coding.CreateTime = time.Now().Format("2006-01-02 15:04:05")
	coding.UpdateTime = time.Now().Format("2006-01-02 15:04:05")
	key := codeListCacheKey
	_ = s.cache.DelBatheHsCache(context.Background(), key)
	return global.GVA_DB.Create(&coding).Error
}

//@author: [piexlmax](https://github.com/piexlmax)
//@function: UpdateLogCoding
//@description: 根据id更新LogCoding
//@param: CodingLog log.CodingLog
//@return: err error
func (s *ServiceLogCoding) UpdateLogCoding(requestCoding request.CodingLogRequest) (err error) {
	logCoding := new(log.CodingLog)
	err = global.GVA_DB.Where("id = ?", requestCoding.Id).First(logCoding).Error
	if err != nil {
		return err
	}
	var coding = make(map[string]interface{})
	coding["coding"] = requestCoding.Coding
	coding["describe"] = requestCoding.Describe
	coding["update_time"] = time.Now().Format("2006-01-02 15:04:05")
	err = global.GVA_DB.Model(&log.CodingLog{}).Where("id", requestCoding.Id).Updates(coding).Error
	if err == nil {
		key := codeListCacheKey
		_ = s.cache.DelBatheHsCache(context.Background(), key)
	}
	return err
}

func (s *ServiceLogCoding) GetCodeById(id int) (coding response.GetLogCodingReply, err error) {
	var api log.CodingLog
	err = global.GVA_DB.Where("id = ?", id).First(&api).Error
	if err != nil {
		return
	}
	coding.Id = api.Id
	coding.Coding = api.Coding
	coding.Describe = api.Describe
	coding.ParentId = api.ParentId
	coding.UpdateTime = api.UpdateTime
	coding.CreateTime = api.CreateTime
	return
}

func (s *ServiceLogCoding) GetCodeLogList(order string, desc bool) (list interface{}, total int64, err error) {
	db := global.GVA_DB.Model(&log.CodingLog{})
	var apiList []log.CodingLog

	err = db.Count(&total).Error
	if err != nil {
		return apiList, total, err
	} else {
		if order != "" {
			var OrderStr string
			// 设置有效排序key 防止sql注入
			// 感谢 Tom4t0 提交漏洞信息
			orderMap := make(map[string]bool, 4)
			orderMap["id"] = true
			if orderMap[order] {
				if desc {
					OrderStr = order + " desc"
				} else {
					OrderStr = order
				}
			} else { // didn't matched any order key in `orderMap`
				//global.GVA_LOG.Error(fmt.Sprintf("非法的排序字段: %v", order))
				return apiList, total, err
			}

			err = db.Order(OrderStr).Find(&apiList).Error
		} else {
			err = db.Order("id").Find(&apiList).Error
		}
	}
	var apisReply []*response.GetCodeListReply
	if len(apiList) != 0 {
		for _, apiInfo := range apiList {
			coding := new(response.GetCodeListReply)
			coding.Id = apiInfo.Id
			coding.Coding = apiInfo.Coding
			coding.Describe = apiInfo.Describe
			coding.ParentId = apiInfo.ParentId
			coding.UpdateTime = apiInfo.UpdateTime
			coding.CreateTime = apiInfo.CreateTime
			coding.Level = apiInfo.Level
			apisReply = append(apisReply, coding)
		}
		mi := make(map[uint]*response.GetCodeListReply)
		for _, item := range apisReply {
			mi[item.Id] = item
		}

		var list1 []*response.GetCodeListReply
		for _, item := range apisReply {
			if item.ParentId == 0 {
				list1 = append(list1, item)
				continue
			}
			if pitem, ok := mi[item.ParentId]; ok {
				pitem.Children = append(pitem.Children, item)
			}
		}
		return list1, total, err
	}

	return apisReply, total, err
}

func (s *ServiceLogCoding) CodeListCache(ctx context.Context, code string) (string, error) {
	key := codeListCacheKey
	status, err := global.GVA_REDIS.Exists(ctx, key).Result()
	if err != nil {
		global.GVA_LOG.Error("获取redis code失败!", zap.Error(err))
		return "", err
	}
	if status == 0 {
		var apiList []log.CodingLog
		err := global.GVA_DB.Model(&log.CodingLog{}).Find(&apiList).Error
		if err != nil {
			global.GVA_LOG.Error("获取表中 code失败!", zap.Error(err))
			return "", err
		}
		mps := make(map[string]string, len(apiList))
		for _, code := range apiList {
			c := strconv.Itoa(code.Coding)
			mps[c] = code.Describe
		}
		err = global.GVA_REDIS.HSet(ctx, key, mps).Err()
		if err != nil {
			global.GVA_LOG.Error("添加到redis code失败!", zap.Error(err))
			return "", err
		}
	}
	c, err := global.GVA_REDIS.HGet(ctx, key, code).Result()
	if err == redis.Nil {
		return code + "没有找数据", nil
	}
	return c, err
}
