package online

import (
	"errors"
	"github.com/gogf/gf/database/gredis"
	"github.com/gogf/gf/util/gconv"
)

const (
	KeyPrefix = "device:onlinestatus:"
)

type Status struct {
	ClientIP          string
	AccessRPCHost     string
	HeartbeatInterval uint32
}

type Manager struct {
	redisClient *gredis.Redis
}

func NewManager(host string, port, db int) *Manager {
	red := gredis.New(&gredis.Config{
		Host:      host,
		Port:      port,
		Db:        db,
		MaxActive: 100,
	})
	mgr := &Manager{
		redisClient: red,
	}
	return mgr
}

func (mgr *Manager) GetStatus(id string) (*Status, error) {
	key := KeyPrefix + id
	status := new(Status)
	// get status from redis
	result, err := mgr.redisClient.DoVar("GET", key)
	if err != nil {
		return nil, err
	}
	err = result.Struct(status)
	if err != nil {
		return nil, err
	}
	return status, nil
}

func (mgr *Manager) GetOnline(id string, status Status) error {
	key := KeyPrefix + id
	buffStr := gconv.String(&status)
	_, err := mgr.redisClient.Do("SET", key, buffStr)
	if err != nil {
		return err
	}
	_, err = mgr.redisClient.Do("EXPIRE", key, status.HeartbeatInterval+status.HeartbeatInterval/2)
	if err != nil {
		return err
	}

	return nil
}

func (mgr *Manager) GetOnlineV2(id string, status Status) error {
	key := KeyPrefix + id
	buffStr := gconv.String(&status)
	_, err := mgr.redisClient.Do("SET", key, buffStr)
	if err != nil {
		return err
	}

	return nil
}

func (mgr *Manager) SetHeartbeat(id string) error {
	status, err := mgr.GetStatus(id)
	if err != nil {
		return err
	}
	if status == nil {
		return errors.New("device offline")
	}

	key := KeyPrefix + id
	_, err = mgr.redisClient.Do("EXPIRE", key, status.HeartbeatInterval+status.HeartbeatInterval/2)
	if err != nil {
		return err
	}

	return nil
}

func (mgr *Manager) GetOffline(id string) error {
	key := KeyPrefix + id
	_, err := mgr.redisClient.Do("DEL", key)
	if err != nil {
		return err
	}

	return nil
}
