/*
 * Copyright 2020-2024 Open Networking Foundation (ONF) and the ONF Contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ponresourcemanager

import (
	"context"
	"encoding/json"
	"errors"
	"strings"
	"testing"
	"time"

	"github.com/boljen/go-bitmap"

	"github.com/opencord/voltha-lib-go/v7/pkg/db"
	"github.com/opencord/voltha-lib-go/v7/pkg/db/kvstore"
	"github.com/opencord/voltha-lib-go/v7/pkg/log"
	"github.com/stretchr/testify/assert"
)

const (
	GEM_POOL_PATH        = "gemport_id_pool"
	RESERVED_GEM_PORT_ID = uint32(5)
)

// MockKVClient mocks the AdapterProxy interface.
type MockResKVClient struct {
	resourceMap map[string]interface{}
}

func newMockKvClient(ctx context.Context) *MockResKVClient {
	var mockResKVClient MockResKVClient
	mockResKVClient.resourceMap = make(map[string]interface{})
	logger.Debug(ctx, "Creating new MockKVClient")
	return &mockResKVClient
}

// List function implemented for KVClient.
func (kvclient *MockResKVClient) List(ctx context.Context, key string) (map[string]*kvstore.KVPair, error) {
	return nil, errors.New("key didn't find")
}

// Get mock function implementation for KVClient
func (kvclient *MockResKVClient) Get(ctx context.Context, key string) (*kvstore.KVPair, error) {
	logger.Debugw(ctx, "Get of MockKVClient called", log.Fields{"key": key})
	if key != "" {
		if strings.Contains(key, RESERVED_GEMPORT_IDS_PATH) {
			logger.Debug(ctx, "Getting Key:", RESERVED_GEMPORT_IDS_PATH)
			reservedGemPorts := []uint32{RESERVED_GEM_PORT_ID}
			str, _ := json.Marshal(reservedGemPorts)
			return kvstore.NewKVPair(key, str, "mock", 3000, 1), nil
		}
		if strings.Contains(key, GEM_POOL_PATH) {
			logger.Debug(ctx, "Getting Key:", GEM_POOL_PATH)
			resource := kvclient.resourceMap[key]
			return kvstore.NewKVPair(key, resource, "mock", 3000, 1), nil
		}
		maps := make(map[string]*kvstore.KVPair)
		maps[key] = &kvstore.KVPair{Key: key}
		return maps[key], nil
	}
	return nil, errors.New("key didn't find")
}

// GetWithPrefix mock function implementation for KVClient
func (kvclient *MockResKVClient) GetWithPrefix(ctx context.Context, prefixKey string) (map[string]*kvstore.KVPair, error) {
	logger.Debugw(ctx, "GetWithPrefix of MockKVClient called", log.Fields{"prefixKey": prefixKey})
	if prefixKey != "" {
		if strings.Contains(prefixKey, GEM_POOL_PATH) {
			logger.Debug(ctx, "Getting keys with prefix:", GEM_POOL_PATH)
			maps := make(map[string]*kvstore.KVPair)
			for key, resource := range kvclient.resourceMap {
				if strings.HasPrefix(key, prefixKey) {
					maps[key] = kvstore.NewKVPair(key, resource, "mock", 3000, 1)
				}
			}
			return maps, nil
		}
	}
	return nil, errors.New("prefixKey didn't find")
}

// GetWithPrefixKeysOnly returns only the keys with the specified prefix.
func (kvclient *MockResKVClient) GetWithPrefixKeysOnly(ctx context.Context, prefixKey string) ([]string, error) {
	logger.Debugw(ctx, "GetWithPrefixKeysOnly of MockKVClient called", log.Fields{"prefixKey": prefixKey})
	if prefixKey != "" {
		if strings.Contains(prefixKey, GEM_POOL_PATH) {
			logger.Debug(ctx, "Getting keys with prefix:", GEM_POOL_PATH)
			var keys []string
			for key := range kvclient.resourceMap {
				if strings.HasPrefix(key, prefixKey) {
					keys = append(keys, key)
				}
			}
			return keys, nil
		}
	}
	return nil, errors.New("prefixKey not found")
}

// Put mock function implementation for KVClient
func (kvclient *MockResKVClient) Put(ctx context.Context, key string, value interface{}) error {
	if key != "" {
		if strings.Contains(key, GEMPORT_ID_POOL_PATH) && value != nil {
			kvclient.resourceMap[key] = value
		}
		return nil
	}
	return errors.New("key didn't find")
}

// Delete mock function implementation for KVClient
func (kvclient *MockResKVClient) Delete(ctx context.Context, key string) error {
	return nil
}

func (c *MockResKVClient) DeleteWithPrefix(ctx context.Context, prefixKey string) error {
	return nil
}

// Reserve mock function implementation for KVClient
func (kvclient *MockResKVClient) Reserve(ctx context.Context, key string, value interface{}, ttl time.Duration) (interface{}, error) {
	return nil, errors.New("key didn't find")
}

// ReleaseReservation mock function implementation for KVClient
func (kvclient *MockResKVClient) ReleaseReservation(ctx context.Context, key string) error {
	return nil
}

// ReleaseAllReservations mock function implementation for KVClient
func (kvclient *MockResKVClient) ReleaseAllReservations(ctx context.Context) error {
	return nil
}

// RenewReservation mock function implementation for KVClient
func (kvclient *MockResKVClient) RenewReservation(ctx context.Context, key string) error {
	return nil
}

// Watch mock function implementation for KVClient
func (kvclient *MockResKVClient) Watch(ctx context.Context, key string, withPrefix bool) chan *kvstore.Event {
	return nil
}

// AcquireLock mock function implementation for KVClient
func (kvclient *MockResKVClient) AcquireLock(ctx context.Context, lockName string, timeout time.Duration) error {
	return nil
}

// ReleaseLock mock function implementation for KVClient
func (kvclient *MockResKVClient) ReleaseLock(lockName string) error {
	return nil
}

// IsConnectionUp mock function implementation for KVClient
func (kvclient *MockResKVClient) IsConnectionUp(ctx context.Context) bool { // timeout in second
	return true
}

// CloseWatch mock function implementation for KVClient
func (kvclient *MockResKVClient) CloseWatch(ctx context.Context, key string, ch chan *kvstore.Event) {
}

// Close mock function implementation for KVClient
func (kvclient *MockResKVClient) Close(ctx context.Context) {
}

func TestExcludeReservedGemPortIdFromThePool(t *testing.T) {
	ctx := context.Background()
	PONRMgr, err := NewPONResourceManager(ctx, "gpon", "onu", "olt1",
		"etcd", "1:1", "service/voltha")
	if err != nil {
		return
	}
	PONRMgr.KVStore = &db.Backend{
		Client: newMockKvClient(ctx),
	}

	PONRMgr.KVStoreForConfig = &db.Backend{
		Client: newMockKvClient(ctx),
	}
	// create a pool in the range of [1,16]
	// and exclude id 5 from this pool
	StartIndex := uint32(1)
	EndIndex := uint32(16)

	reservedGemPortIds, defined := PONRMgr.getReservedGemPortIdsFromKVStore(ctx)
	if !defined {
		return
	}

	FormatResult, err := PONRMgr.FormatResource(ctx, 1, StartIndex, EndIndex, reservedGemPortIds)
	if err != nil {
		t.Error("Failed to format resource", err)
		return
	}

	// Add resource as json in kv store.
	err = PONRMgr.KVStore.Put(ctx, GEMPORT_ID_POOL_PATH, FormatResult)
	if err != nil {
		t.Error("Error in posting data to kv store", GEMPORT_ID_POOL_PATH)
		return
	}

	for i := StartIndex; i <= (EndIndex - uint32(len(reservedGemPortIds))); i++ {
		// get gem port id pool from the kv store
		resource, err := PONRMgr.GetResource(context.Background(), GEMPORT_ID_POOL_PATH)
		if err != nil {
			t.Error("Failed to get resource from gem port id pool", err)
			return
		}
		// get a gem port id from the pool
		nextID, err := PONRMgr.GenerateNextID(ctx, resource)
		if err != nil {
			t.Error("Failed to get gem port id from the pool", err)
			return
		}

		//given gem port id should not equal to the reserved gem port id
		assert.NotEqual(t, nextID, RESERVED_GEM_PORT_ID)
		// put updated gem port id pool into the kv store
		err = PONRMgr.UpdateResource(context.Background(), GEMPORT_ID_POOL_PATH, resource)
		if err != nil {
			t.Error("Failed to put updated gem port id pool into the kv store", err)
			return
		}
	}

}

func TestResourcePoolOverflow(t *testing.T) {
	ctx := context.Background()
	PONRMgr, err := NewPONResourceManager(ctx, "gpon", "onu", "olt1",
		"etcd", "1:1", "service/voltha")
	if err != nil {
		return
	}
	PONRMgr.KVStore = &db.Backend{
		Client: newMockKvClient(ctx),
	}

	PONRMgr.KVStoreForConfig = &db.Backend{
		Client: newMockKvClient(ctx),
	}
	// create a pool in the range of [1,16]
	StartIndex := uint32(1)
	EndIndex := uint32(16)

	FormatResult, err := PONRMgr.FormatResource(ctx, 1, StartIndex, EndIndex, []uint32{})
	if err != nil {
		t.Error("Failed to format resource", err)
		return
	}

	// Add resource as json in kv store.
	err = PONRMgr.KVStore.Put(ctx, GEMPORT_ID_POOL_PATH, FormatResult)
	if err != nil {
		t.Error("Error in posting data to kv store", GEMPORT_ID_POOL_PATH)
		return
	}

	for i := 1; i <= 20; i++ {
		// get gem port id pool from the kv store
		resource, err := PONRMgr.GetResource(context.Background(), GEMPORT_ID_POOL_PATH)
		if err != nil {
			t.Error("Failed to get resource from gem port id pool", err)
			return
		}
		// get a gem port id from the pool
		nextID, err := PONRMgr.GenerateNextID(ctx, resource)
		// all free ids in the pool will be consumed by the first 16 steps of the loop
		// resource-exhausted error is expected from the pool at the 17th step of the loop
		if i > int(EndIndex) {
			assert.NotNil(t, err)
		} else if err != nil {
			t.Error("Failed to get gem port id from the pool", err)
			return
		} else {
			assert.NotEqual(t, 0, nextID)
			// put updated gem port id pool into the kv store
			err = PONRMgr.UpdateResource(context.Background(), GEMPORT_ID_POOL_PATH, resource)
			if err != nil {
				t.Error("Failed to put updated gem port id pool into the kv store", err)
				return
			}
		}
	}
}

func TestPONResourceManager_ReleaseInvalidID(t *testing.T) {
	ctx := context.Background()
	PONRMgr, err := NewPONResourceManager(ctx, "gpon", "onu", "olt1",
		"etcd", "1:1", "service/voltha")
	if err != nil {
		return
	}
	PONRMgr.KVStore = &db.Backend{
		Client: newMockKvClient(ctx),
	}

	PONRMgr.KVStoreForConfig = &db.Backend{
		Client: newMockKvClient(ctx),
	}
	// create a pool in the range of [1,16]
	StartIndex := uint32(1)
	EndIndex := uint32(16)

	FormatResult, err := PONRMgr.FormatResource(ctx, 1, StartIndex, EndIndex, []uint32{})
	if err != nil {
		t.Error("Failed to format resource", err)
		return
	}

	// Add resource as json in kv store.
	err = PONRMgr.KVStore.Put(ctx, GEMPORT_ID_POOL_PATH, FormatResult)
	if err != nil {
		t.Error("Error in posting data to kv store", GEMPORT_ID_POOL_PATH)
		return
	}

	// get gem port id pool from the kv store
	resource, err := PONRMgr.GetResource(context.Background(), GEMPORT_ID_POOL_PATH)
	if err != nil {
		t.Error("Failed to get resource from gem port id pool", err)
		return
	}
	//try to release an ID whose value is out of the boundaries of the pool and expect false
	released := PONRMgr.ReleaseID(ctx, resource, uint32(EndIndex+1))
	assert.Equal(t, false, released)
}

func TestPONResourceManager_ReserveInvalidID(t *testing.T) {
	ctx := context.Background()
	PONRMgr, err := NewPONResourceManager(ctx, "gpon", "onu", "olt1",
		"etcd", "1:1", "service/voltha")
	if err != nil {
		return
	}
	PONRMgr.KVStore = &db.Backend{
		Client: newMockKvClient(ctx),
	}

	PONRMgr.KVStoreForConfig = &db.Backend{
		Client: newMockKvClient(ctx),
	}
	// create a pool in the range of [1,16]
	StartIndex := uint32(1)
	EndIndex := uint32(16)

	FormatResult, err := PONRMgr.FormatResource(ctx, 1, StartIndex, EndIndex, []uint32{})
	if err != nil {
		t.Error("Failed to format resource", err)
		return
	}

	// Add resource as json in kv store.
	err = PONRMgr.KVStore.Put(ctx, GEMPORT_ID_POOL_PATH, FormatResult)
	if err != nil {
		t.Error("Error in posting data to kv store", GEMPORT_ID_POOL_PATH)
		return
	}
	// get gem port id pool from the kv store
	resource, err := PONRMgr.GetResource(context.Background(), GEMPORT_ID_POOL_PATH)
	if err != nil {
		t.Error("Failed to get resource from gem port id pool", err)
		return
	}
	ByteArray, err := ToByte(resource[POOL])
	if err != nil {
		t.Error(ctx, "Failed to convert resource to byte array")
		return
	}
	Data := bitmap.TSFromData(ByteArray, false)
	if Data == nil {
		t.Error(ctx, "Failed to get resource pool")
		return
	}
	//try to reserve an ID whose value is out of the boundaries of the pool and expect false
	reserved := PONRMgr.reserveID(ctx, Data, StartIndex, EndIndex+1)
	assert.Equal(t, false, reserved)
}
