package nnet

import (
	"math/rand"
	"sync"
	"time"
)

var (
// Hub 状态
)

type HubConfig struct {
	SizeOfSendChan uint32
	SizeOfRecvChan uint32
	ReadBufSize    int
	WriteBufSize   int
	Timeout        time.Duration // 发送等超时
	Tick           time.Duration // 定时回调
	ReadTimeout    time.Duration // 讀超時，如果為0，則無限等待。超時到達，意味著客戶端心跳丟失
}

type IHub interface {
	Lock() // support locker semantics
	Unlock()

	Wg() *sync.WaitGroup        // object
	ChQuit() <-chan struct{}    // 返回一个通道，用于退出 hub 循环
	Conf() *HubConfig           // 返回配置信息
	Callback() ISessionCallback // 返回回调对象
	Protocol() IProtocol        // 返回数据协议

	Start() error // 启动 hub
	Stop() error  // 停止 hub
	DoJob(int)    // 执行 hub 中其他任务

	PutSession(uint64, ISession) error // session 管理，这里的 session 必须基于　id
	DelSession(uint64) error
	GetSession(uint64) (ISession, error)
	PeekSession(uint64) (ISession, error)
	RandSession() (ISession, error)
	GetSessionNum() int
	GetAllSessions() map[uint64]ISession
}

type Hub struct {
	sync.Mutex
	conf   *HubConfig
	cbSes  ISessionCallback
	prot   IProtocol
	chQuit chan struct{}
	wg     *sync.WaitGroup

	sess map[uint64]ISession
}

func newHub(cf *HubConfig, cb ISessionCallback, p IProtocol) *Hub {
	return &Hub{
		conf:   cf,
		cbSes:  cb,
		prot:   p,
		chQuit: make(chan struct{}),
		wg:     &sync.WaitGroup{},
		sess:   make(map[uint64]ISession),
	}
}

func (self *Hub) Wg() *sync.WaitGroup {
	return self.wg
}

func (self *Hub) ChQuit() <-chan struct{} {
	return self.chQuit
}

func (self *Hub) Conf() *HubConfig {
	return self.conf
}

func (self *Hub) Callback() ISessionCallback {
	return self.cbSes
}

func (self *Hub) Protocol() IProtocol {
	return self.prot
}

func (self *Hub) PutSession(id uint64, ses ISession) error {
	self.Lock()
	//@Notice: 顶替
	self.sess[id] = ses
	self.Unlock()
	return nil
}

func (self *Hub) DelSession(id uint64) error {
	self.Lock()
	defer self.Unlock()

	if _, ok := self.sess[id]; !ok {
		return ErrNotExists
	}
	delete(self.sess, id)
	return nil
}

func (self *Hub) PeekSession(id uint64) (ISession, error) {
	self.Lock()
	defer self.Unlock()

	s, ok := self.sess[id]
	if !ok {
		return nil, ErrNotExists
	}

	delete(self.sess, id)

	return s, nil
}

func (self *Hub) GetSession(id uint64) (ISession, error) {
	self.Lock()
	defer self.Unlock()

	s, ok := self.sess[id]
	if !ok {
		return nil, ErrNotExists
	}
	return s, nil
}

func (self *Hub) GetAllSessions() map[uint64]ISession {
	self.Lock()
	defer self.Unlock()

	return self.sess
}

var (
	s = rand.NewSource(time.Now().UnixNano())
	r = rand.New(s)
)

func Intn(a int) int {
	return r.Intn(a)
}

func (self *Hub) RandSession() (ISession, error) {
	self.Lock()
	defer self.Unlock()

	sz := len(self.sess)

	sel := Intn(sz)
	counter := 0
	for _, ses := range self.sess {
		if counter == sel {
			return ses, nil
		}
		counter += 1
	}
	return nil, ErrNotExists
}

func (self *Hub) GetSessionNum() int {
	self.Lock()
	defer self.Unlock()
	return len(self.sess)
}
