package rank_util

import (
	"fmt"
	"goutil/mathUtil"
	"math"
	"strconv"
	"sync"
	"testing"
	"time"
)

func Test_Rank(t *testing.T) {
	r := NewRankUtil(20, compar)

	dc := make(map[string]*rmodel)
	for i := 1; i < 1000; i++ {
		tk := strconv.Itoa(i)
		m := &rmodel{k: tk, Fap: 0}
		dc[m.k] = m
	}

	goCount := 10
	srand := mathUtil.GetRand()
	var wg sync.WaitGroup
	wg.Add(goCount)
	for i := 0; i < goCount; i++ {
		go func() {
			for i := 1; i < 1000; i++ {
				tk := strconv.Itoa(i)
				newf := srand.GetRandRangeInt(1, 1000)

				m, _ := dc[tk]
				isUp := m.Fap < newf
				m.Fap = newf
				r.Refresh(tk, m, isUp)
			}
		}()

		time.Sleep(time.Second)
		wg.Done()
	}

	wg.Wait()
	items := r.GetAll()
	if len(items) != r.maxCount {
		t.Error("排行榜长度不为", r.maxCount)
	}

	//测试删除
	r.Delete(r.GetItemForRank(1).key)
	items = r.GetAll()
	if len(items) != r.maxCount-1 {
		t.Error("删除后的排行榜长度不为", r.maxCount-1)
	}

	//校验标准： 1.key不可以重复 2.fap越来越小
	beforeFap := math.MaxInt
	tempKeyDict := make(map[string]bool)
	isPrintAll := false
	for _, item := range items {
		m := item.obj.(*rmodel)
		if m.k != item.key {
			t.Errorf("错误：item.key!=m.k  item.key:%s m.k:%s", item.key, m.k)
			isPrintAll = true
		}

		//  校验1
		if _, exist := tempKeyDict[item.key]; exist {
			t.Errorf("错误：item.key重复 item.key:%s m.k:%s", item.key, m.k)
			isPrintAll = true
		} else {
			tempKeyDict[item.key] = false
		}

		//  校验2
		if m.Fap > beforeFap {
			t.Errorf("错误：m.Fap大于前面的排行 beforeFap:%v curFap:%v", beforeFap, m.Fap)
			isPrintAll = true
		}
	}

	if isPrintAll {
		for _, item := range items {
			m := item.obj.(*rmodel)
			t.Log(m)
		}
	}

}

func Test_Rank2(t *testing.T) {
	r := NewRankUtil(5, compar)
	r.Refresh("1", &rmodel{k: "1", Fap: 1}, true)
	r.Refresh("2", &rmodel{k: "2", Fap: 2}, true)
	r.Refresh("3", &rmodel{k: "3", Fap: 3}, true)
	r.Refresh("4", &rmodel{k: "4", Fap: 4}, true)
	r.Refresh("5", &rmodel{k: "5", Fap: 5}, true)

	//把1挤出去
	ischange, dm := r.Refresh("6", &rmodel{k: "6", Fap: 6}, true)
	if ischange == false {
		t.Errorf("把1挤出去错误，排行榜未变动")
		return
	}
	if dm.key != "1" {
		t.Errorf("把1挤出去错误，挤出的不是1")
		return
	}
	t.Log("被挤出的对象信息-> ", dm)

	//打印所有
	items := r.GetAll()
	for _, item := range items {
		t.Log(item)
	}
}

type rmodel struct {
	k   string
	Fap int
}

func (m *rmodel) String() string {
	return fmt.Sprintf("m.k:%s fap:%v", m.k, m.Fap)
}

// compar
// @description: 判断对象大小,返回含义 -1:a<b 0:a=b 1:a>b
// parameter:
//
//	@a:对象a
//	@b:对象b
//
// return:
//
//	@int:
func compar(a, b interface{}) int {
	af := a.(*rmodel).Fap
	bf := b.(*rmodel).Fap
	if af > bf {
		return 1
	} else if af == bf {
		return 0
	} else {
		return -1
	}
}
