package fusenrender

import (
	"context"
	"encoding/gob"
	"fmt"
	"io"
	"runtime"
	"sync"
	"time"

	"github.com/474420502/execute/triggered"
	sm "github.com/lni/dragonboat/v4/statemachine"
)

// SMQueue实现了StateMachine接口,用于管理基于PriorityQueue的消息队列
type SMQueue struct {
	// 所属的Shard ID
	shardID uint64
	// Replica ID
	replicaID uint64

	// 互斥锁,保护队列Map的并发访问
	mu *sync.Mutex
	// 组名到队列的映射
	queues  map[string]*PriorityQueue[QueueItem]
	counter *triggered.EventExecute[int64]
}

// // NewSMQueue creates and return a new ExampleStateMachine object.
func NewSMQueue(shardID uint64, replicaID uint64) sm.IStateMachine {
	mu := &sync.Mutex{}
	return &SMQueue{
		shardID:   shardID,
		replicaID: replicaID,

		mu:     mu,
		queues: make(map[string]*PriorityQueue[QueueItem]),

		counter: triggered.RegisterExecute[int64](func(params *triggered.Params[int64]) {
			if params.Value != 0 {
				var m runtime.MemStats
				runtime.ReadMemStats(&m)
				allocMB := float64(m.Alloc) / 1024 / 1024
				totalAllocMB := float64(m.TotalAlloc) / 1024 / 1024
				sysMB := float64(m.Sys) / 1024 / 1024
				fmt.Printf("queue remain: %d, Alloc = %.2f MB, TotalAlloc = %.2f MB, Sys = %.2f MB\n", params.Value, allocMB, totalAllocMB, sysMB)

				time.Sleep(time.Second * 5)
			} else {
				time.Sleep(time.Second * 15)
			}
		}),
	}
}

// Lookup performs local lookup on the ExampleStateMachine instance. In this example,
// we always return the Count value as a little endian binary encoded byte
// slice.
func (s *SMQueue) Lookup(group interface{}) (item interface{}, err error) {
	return item, nil
}

type ctxEntry struct{}
type ctxSMQueue struct{}
type ctxDequeueHandler struct{}

// Update处理Entry中的更新命令
// Update updates the object using the specified committed raft entry.
func (s *SMQueue) Update(e sm.Entry) (result sm.Result, err error) {
	ctx := context.TODO()

	ctx = context.WithValue(ctx, ctxEntry{}, &e)
	ctx = context.WithValue(ctx, ctxSMQueue{}, s)
	ctx = context.WithValue(ctx, ctxDequeueHandler{}, DequeueHandler)
	return FsPasser.ExecuteWithBytes(ctx, e.Cmd)
}

// SaveSnapshot saves the current IStateMachine state into a snapshot using the
// specified io.Writer object.
func (s *SMQueue) SaveSnapshot(w io.Writer,
	fc sm.ISnapshotFileCollection, done <-chan struct{}) error {
	// as shown above, the only state that can be saved is the Count variable
	// there is no external file in this IStateMachine example, we thus leave
	// the fc untouched

	s.mu.Lock()
	defer s.mu.Unlock()

	return gob.NewEncoder(w).Encode(&s.queues)
	// return nil
}

// RecoverFromSnapshot recovers the state using the provided snapshot.
func (s *SMQueue) RecoverFromSnapshot(r io.Reader,
	files []sm.SnapshotFile,
	done <-chan struct{}) error {
	// restore the Count variable, that is the only state we maintain in this
	// example, the input files is expected to be empty

	err := gob.NewDecoder(r).Decode(&s.queues)
	if err != nil {
		return err
	}

	return nil
}

// Close closes the IStateMachine instance. There is nothing for us to cleanup
// or release as this is a pure in memory data store. Note that the Close
// method is not guaranteed to be called as node can crash at any time.
func (s *SMQueue) Close() error { return nil }