package front

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis"
	"gorm.io/gorm"
	"sync"
	"worktest/pkg/controller"
	"worktest/pkg/model"
	"worktest/pkg/redistab"
)

type ListReq struct {
	Title  string `json:"'title'"`
	UserId uint   `json:"'userId'"`
}

type DetailReq struct {
	ID     uint
	UserId uint `json:"'userId'"`
}

var synMysqlToRedisLock sync.RWMutex

func MysqlList(c *gin.Context) {
	var req ListReq
	if err := c.ShouldBind(&req); err != nil {
		controller.Error(c, err.Error())
		return
	}

	var list []*model.Product
	model.DB.Model(&model.Product{}).Find(&list)
	fmt.Println("2--------", redistab.RedisClient)

	controller.Success(c, list)

	return

}

func RedisBuy(c *gin.Context) {
	var req DetailReq
	if err := c.ShouldBind(&req); err != nil {
		controller.Error(c, err.Error())
		return
	}

	var list []*model.Product
	model.DB.Model(&model.Product{}).Find(&list)

	err := model.DB.Transaction(func(tx *gorm.DB) error {
		var obj *model.Product
		if err := model.DB.Model(&model.Product{}).First(&obj, req.ID).Error; err != nil {
			return err
		}

		if obj.StockSize <= 0 {
			return errors.New("库存不足")
		}

		//生成订单
		productOrder := &model.ProductOrder{
			ProductID: req.ID,
			UserId:    req.UserId,
		}
		if err := model.DB.Model(&model.ProductOrder{}).Create(&productOrder).Error; err != nil {
			return err
		}

		//扣除库存
		model.DB.Model(&model.Product{}).Where(&model.Product{ID: req.ID}).UpdateColumn("stock_size", gorm.Expr("stock_size - 1"))

		return nil
	})

	if err != nil {
		controller.Error(c, err.Error())
		return

	}

	fmt.Println("2--------", redistab.RedisClient)

	controller.Success(c, list)

	return

}

func MysqlBuy(c *gin.Context) {
	var req DetailReq
	if err := c.ShouldBind(&req); err != nil {
		controller.Error(c, err.Error())
		return
	}

	var list []*model.Product
	model.DB.Model(&model.Product{}).Find(&list)

	err := model.DB.Transaction(func(tx *gorm.DB) error {
		var obj *model.Product
		if err := model.DB.Model(&model.Product{}).First(&obj, req.ID).Error; err != nil {
			return err
		}

		if obj.StockSize <= 0 {
			return errors.New("库存不足")
		}

		//生成订单
		productOrder := &model.ProductOrder{
			ProductID: req.ID,
			UserId:    req.UserId,
		}
		if err := model.DB.Model(&model.ProductOrder{}).Create(&productOrder).Error; err != nil {
			return err
		}

		//扣除库存
		model.DB.Model(&model.Product{}).Where(&model.Product{ID: req.ID}).UpdateColumn("stock_size", gorm.Expr("stock_size - 1"))

		return nil
	})

	if err != nil {
		controller.Error(c, err.Error())
		return

	}

	fmt.Println("2--------", redistab.RedisClient)

	controller.Success(c, list)

	return

}

func RedisList(c *gin.Context) {
	var req ListReq
	if err := c.ShouldBind(&req); err != nil {
		controller.Error(c, err.Error())
		return
	}

	var list []*model.Product
	model.DB.Model(&model.Product{}).Find(&list)
	fmt.Println("2--------", redistab.RedisClient)

	controller.Success(c, list)
	//统计人获取的次数
	return
}

func MysqlDetail(c *gin.Context) {
	var req DetailReq
	if err := c.ShouldBind(&req); err != nil {
		controller.Error(c, err.Error())
		return
	}

	var productObj *model.Product
	if err := model.DB.Model(&model.Product{}).First(&productObj, req.ID).Error; err != nil {
		controller.Error(c, err.Error())
		return
	}

	controller.Success(c, productObj)
	return
}

func RedisDetail(c *gin.Context) {
	var productObj *model.Product
	var req DetailReq

	if err := c.ShouldBind(&req); err != nil {
		controller.Error(c, err.Error())
		return
	}

	v, err := redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result()

	//无缓存 则去mysql同步数据
	if err != nil {
		var tempObj *model.Product
		if err := model.DB.Model(&model.Product{}).First(&tempObj, req.ID).Error; err != nil {
			controller.Error(c, err.Error())
			return
		}

		b, err := json.Marshal(tempObj)
		if err != nil {
			controller.Error(c, err.Error())
			return
		}

		v, err = redistab.RedisClient.Set(redistab.GetProductDetail(req.ID), string(b), 0).Result()
		fmt.Println("1---------", v, err)

		if err != nil {
			controller.Error(c, err.Error())
			return
		}

		v, _ = redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result()
	}

	err = json.Unmarshal([]byte(v), &productObj)
	if err != nil {
		controller.Error(c, err.Error())
		return
	}

	controller.Success(c, productObj)
	return
}

func RedisDetailLock(c *gin.Context) {
	var productObj *model.Product
	var req DetailReq

	if err := c.ShouldBind(&req); err != nil {
		controller.Error(c, err.Error())
		return
	}

	v, err := redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result()

	//无缓存 则去mysql同步数据
	if err != nil {
		synMysqlToRedisLock.Lock()
		defer synMysqlToRedisLock.Lock()

		var tempObj *model.Product
		if err := model.DB.Model(&model.Product{}).First(&tempObj, req.ID).Error; err != nil {
			controller.Error(c, err.Error())
			return
		}

		b, err := json.Marshal(tempObj)
		if err != nil {
			controller.Error(c, err.Error())
			return
		}

		v, err = redistab.RedisClient.Set(redistab.GetProductDetail(req.ID), string(b), 0).Result()
		fmt.Println("1---------", v, err)

		if err != nil {
			controller.Error(c, err.Error())
			return
		}

		v, _ = redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result()
	}

	err = json.Unmarshal([]byte(v), &productObj)
	if err != nil {
		controller.Error(c, err.Error())
		return
	}

	controller.Success(c, productObj)
	return
}

func RedisDetailBitMap(c *gin.Context) {
	var productObj *model.Product
	var req DetailReq

	if err := c.ShouldBind(&req); err != nil {
		controller.Error(c, err.Error())
		return
	}

	v, err := redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result()

	//bitmap
	bit, err := redistab.RedisClient.GetBit(redistab.GetProductBitMap(), int64(req.ID)).Result()

	fmt.Println("2----------", bit, err)
	if bit == 0 { //不存在
		controller.Error(c, "非法数据")
		return
	}

	//无缓存 则去mysql同步数据
	if err != nil {
		synMysqlToRedisLock.Lock()
		defer synMysqlToRedisLock.Lock()

		var tempObj *model.Product
		if err := model.DB.Model(&model.Product{}).First(&tempObj, req.ID).Error; err != nil {
			controller.Error(c, err.Error())
			return
		}

		b, err := json.Marshal(tempObj)
		if err != nil {
			controller.Error(c, err.Error())
			return
		}

		v, err = redistab.RedisClient.Set(redistab.GetProductDetail(req.ID), string(b), 0).Result()
		fmt.Println("1---------", v, err)

		if err != nil {
			controller.Error(c, err.Error())
			return
		}

		v, _ = redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result()
	}

	err = json.Unmarshal([]byte(v), &productObj)
	if err != nil {
		controller.Error(c, err.Error())
		return
	}

	//增加统计,增加去重统计 该商品的DAU
	_, _ = redistab.RedisClient.PFAdd(redistab.GetProductDetailLogCount(req.ID)).Result()

	controller.Success(c, productObj)
	return
}

func RedisCountProduct(c *gin.Context) {
	var req DetailReq

	if err := c.ShouldBind(&req); err != nil {
		controller.Error(c, err.Error())
		return
	}

	//增加统计,增加去重统计 该商品的DAU
	_ = &redis.BitCount{
		Start: 1,
		End:   1,
	}

	b, _ := redistab.RedisClient.BitCount(redistab.GetProductBitMap(), nil).Result()

	controller.Success(c, b)
	return
}

func RedisDetailBitMapCount(c *gin.Context) {
	var productObj *model.Product
	var req DetailReq

	if err := c.ShouldBind(&req); err != nil {
		controller.Error(c, err.Error())
		return
	}

	v, err := redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result()

	//bitmap
	bit, err := redistab.RedisClient.GetBit(redistab.GetProductBitMap(), int64(req.ID)).Result()

	fmt.Println("2----------", bit, err)
	if bit == 0 { //不存在
		controller.Error(c, "非法数据")
		return
	}

	//无缓存 则去mysql同步数据
	if err != nil {
		synMysqlToRedisLock.Lock()
		defer synMysqlToRedisLock.Lock()

		var tempObj *model.Product
		if err := model.DB.Model(&model.Product{}).First(&tempObj, req.ID).Error; err != nil {
			controller.Error(c, err.Error())
			return
		}

		b, err := json.Marshal(tempObj)
		if err != nil {
			controller.Error(c, err.Error())
			return
		}

		v, err = redistab.RedisClient.Set(redistab.GetProductDetail(req.ID), string(b), 0).Result()
		fmt.Println("1---------", v, err)

		if err != nil {
			controller.Error(c, err.Error())
			return
		}

		v, _ = redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result()
	}

	err = json.Unmarshal([]byte(v), &productObj)
	if err != nil {
		controller.Error(c, err.Error())
		return
	}

	//增加统计,增加去重统计 该商品的DAU
	_, _ = redistab.RedisClient.PFAdd(redistab.GetProductDetailLogCount(req.ID)).Result()

	controller.Success(c, productObj)
	return
}