package nodemanager

import (
	"context"
	"os"
	"strconv"
	"strings"
	"testing"

	"github.com/pingcap/log"
	"github.com/stretchr/testify/assert"
	rm "github.com/tidbcloud/aws-shared-provider/pkg/tidbworker/resourcemanager/types"
	"github.com/tidbcloud/aws-shared-provider/pkg/utils/tidb"
	"go.uber.org/zap"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

func TestBind(t *testing.T) {
	ctx := context.Background()
	db, err := gorm.Open(sqlite.Open("/tmp/TestMysqlBindHandler.db"), &gorm.Config{})
	assert.NoError(t, err)
	defer func() {
		err = os.Remove("/tmp/TestMysqlBindHandler.db")
		assert.NoError(t, err)
	}()
	_ = db.WithContext(ctx).AutoMigrate(&Node{})
	binder := NewBinder(db)

	poolName := "default"
	testKS := "test_ks"

	nodeCount := 5
	for i := 0; i < nodeCount; i++ {
		err = binder.InsertNewNode(ctx, poolName+"_"+strconv.Itoa(i), poolName)
		assert.NoError(t, err)
	}

	// check nodes count.
	nodes, err := binder.GetAllNodes(ctx)
	assert.Equal(t, nodeCount, len(nodes))
	log.Info("nodes:", zap.Any("nodes", nodes))

	// Bind 1 node.
	taskID01 := "ks1_task_id_1"
	req := &Request{
		TaskID:          taskID01,
		ActivateRequest: tidb.ActivateRequest{KeyspaceName: testKS},
		PoolName:        rm.WorkerPool(poolName),
	}
	requests := []*Request{req}
	nodes, err = binder.Bind(ctx, 1, requests)
	assert.NoError(t, err)
	bindResNodeCount := len(nodes)
	assert.Equal(t, 1, bindResNodeCount)

	// Bind another one.
	req02 := &Request{
		TaskID:          "test_bind02",
		ActivateRequest: tidb.ActivateRequest{KeyspaceName: testKS},
		PoolName:        rm.WorkerPool(poolName),
	}
	requests02 := []*Request{req02}
	nodes02, err := binder.Bind(ctx, 1, requests02)
	assert.NoError(t, err)
	bindResNodeCount = len(nodes02)
	assert.Equal(t, 1, bindResNodeCount)

	// Check get node by first node name.
	nodeID01 := nodes[0]
	expectNodeID := nodeID01.NodeID
	node, err := binder.GetNodeByNodeID(ctx, expectNodeID)
	log.Info("node:", zap.Any("node", node))
	assert.Equal(t, expectNodeID, node.NodeID)
	assert.Equal(t, poolName, node.PoolName)

	// Unbind the first node.
	_, err = binder.Unbind(ctx, []string{taskID01})
	assert.NoError(t, err)

	// Check unbind result.
	lockAfterUnbind, err := binder.GetNodeByTaskID(ctx, taskID01)
	assert.True(t, strings.Contains(err.Error(), "record not found"))
	assert.Nil(t, lockAfterUnbind)
	unbindLock, err := binder.GetNodeByNodeID(ctx, nodeID01.NodeID)
	assert.NotNil(t, unbindLock)
	assert.Equal(t, "", unbindLock.TaskID)
	assert.Equal(t, "", unbindLock.ActivateRequest)
	assert.False(t, unbindLock.IsBound)
}
