package ticktock

import (
	"context"
	"fmt"
	"time"

	"gitlink.org.cn/cloudream/common/pkgs/logger"
	"gitlink.org.cn/cloudream/common/utils/reflect2"
	"gitlink.org.cn/cloudream/jcs-pub/common/consts"
	stgglb "gitlink.org.cn/cloudream/jcs-pub/common/globals"
	hubrpc "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/rpc/hub"
	cortypes "gitlink.org.cn/cloudream/jcs-pub/coordinator/types"
)

type CheckHubState struct {
}

func (j *CheckHubState) Name() string {
	return reflect2.TypeNameOf[CheckHubState]()
}

func (j *CheckHubState) Execute(t *TickTock) {
	log := logger.WithType[CheckHubState]("TickTock")
	log.Debugf("job start")
	startTime := time.Now()
	defer func() {
		log.Debugf("job end, time: %v", time.Since(startTime))
	}()

	hubs, err := t.db.Hub().GetAllHubs(t.db.DefCtx())
	if err != nil {
		log.Warnf("get all hubs: %s", err.Error())
		return
	}

	for _, hub := range hubs {
		err := j.checkOne(t, hub)
		if err != nil {
			log.Warnf("check one hub %v: %s", hub, err.Error())
		}
	}
}

func (j *CheckHubState) checkOne(t *TickTock, hub cortypes.Hub) error {
	log := logger.WithType[CheckHubState]("TickTock")

	addr, ok := hub.Address.(*cortypes.GRPCAddressInfo)
	if !ok {
		return fmt.Errorf("hub has no grpc address")
	}

	agtCli := stgglb.HubRPCPool.Get(stgglb.SelectGRPCAddress(hub, *addr))
	defer agtCli.Release()

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	_, cerr := agtCli.GetState(ctx, &hubrpc.GetState{})
	if cerr != nil {
		if hub.LastReportTime != nil {
			if time.Since(*hub.LastReportTime) > t.cfg.HubUnavailableTime {
				err := t.db.Hub().UpdateState(t.db.DefCtx(), hub.HubID, consts.HubStateUnavailable)
				if err != nil {
					log.Warnf("set hub %v state: %s", hub, err.Error())
				}
			}

		} else if hub.LastReportTime == nil {
			err := t.db.Hub().UpdateState(t.db.DefCtx(), hub.HubID, consts.HubStateUnavailable)
			if err != nil {
				log.Warnf("set hub %v state: %s", hub, err.Error())
			}
		}

		return fmt.Errorf("getting state: %w", cerr)
	}

	// TODO 如果以后还有其他的状态，要判断哪些状态下能设置Normal
	err := t.db.Hub().UpdateState(t.db.DefCtx(), hub.HubID, consts.HubStateNormal)
	if err != nil {
		log.Warnf("set hub %v state: %s", hub, err.Error())
	}

	return nil
}
