package metacache

import (
	"time"

	"gitlink.org.cn/cloudream/common/pkgs/logger"
	"gitlink.org.cn/cloudream/jcs-pub/client/types"
	stgglb "gitlink.org.cn/cloudream/jcs-pub/common/globals"
	"gitlink.org.cn/cloudream/jcs-pub/common/pkgs/mq/coordinator"
	cortypes "gitlink.org.cn/cloudream/jcs-pub/coordinator/types"
)

func (m *MetaCacheHost) AddStorageMeta() *UserSpaceMeta {
	meta := &UserSpaceMeta{
		host: m,
	}
	meta.cache = NewSimpleMetaCache(SimpleMetaCacheConfig[types.UserSpaceID, types.UserSpaceDetail]{
		Getter: meta.load,
		Expire: time.Minute * 5,
	})

	m.caches = append(m.caches, meta)
	return meta
}

type UserSpaceMeta struct {
	host  *MetaCacheHost
	cache *SimpleMetaCache[types.UserSpaceID, types.UserSpaceDetail]
}

func (s *UserSpaceMeta) Get(spaceID types.UserSpaceID) *types.UserSpaceDetail {
	v, ok := s.cache.Get(spaceID)
	if ok {
		return &v
	}
	return nil
}

func (s *UserSpaceMeta) GetMany(spaceIDs []types.UserSpaceID) []*types.UserSpaceDetail {
	vs, oks := s.cache.GetMany(spaceIDs)
	ret := make([]*types.UserSpaceDetail, len(vs))
	for i := range vs {
		if oks[i] {
			ret[i] = &vs[i]
		}
	}
	return ret
}

func (s *UserSpaceMeta) ClearOutdated() {
	s.cache.ClearOutdated()
}

func (s *UserSpaceMeta) load(keys []types.UserSpaceID) ([]types.UserSpaceDetail, []bool) {
	vs := make([]types.UserSpaceDetail, len(keys))
	oks := make([]bool, len(keys))

	spaces, err := s.host.db.UserSpace().BatchGetByID(s.host.db.DefCtx(), keys)
	if err != nil {
		logger.Warnf("batch get user space by id: %v", err)
		return vs, oks
	}

	coorCli, err := stgglb.CoordinatorMQPool.Acquire()
	if err != nil {
		logger.Warnf("new coordinator client: %v", err)
		return vs, oks
	}
	defer stgglb.CoordinatorMQPool.Release(coorCli)

	stgIDs := make([]cortypes.StorageID, len(spaces))
	for i := range spaces {
		stgIDs[i] = spaces[i].StorageID
	}

	getStgs, err := coorCli.GetStorageDetails(coordinator.ReqGetStorageDetails(stgIDs))
	if err != nil {
		logger.Warnf("get storage details: %v", err)
		return vs, oks
	}

	for i := range spaces {
		if getStgs.Storage[i] != nil {
			vs[i] = types.UserSpaceDetail{
				UserID:    stgglb.Local.UserID,
				UserSpace: spaces[i],
				Storage:   getStgs.Storage[i].Storage,
				MasterHub: getStgs.Storage[i].MasterHub,
			}

			oks[i] = true
		}
	}

	return vs, oks
}
