/*
 * Copyright 2018-present Open Networking Foundation

 * 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 kvstore

import (
	"context"
	"errors"
	"fmt"
	"github.com/opencord/voltha-lib-go/pkg/common/log"
	v3Client "go.etcd.io/etcd/clientv3"
	v3Concurrency "go.etcd.io/etcd/clientv3/concurrency"
	v3rpcTypes "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes"
	"sync"
)

// EtcdClient represents the Etcd KV store client
type EtcdClient struct {
	ectdAPI          *v3Client.Client
	leaderRev        v3Client.Client
	keyReservations  map[string]*v3Client.LeaseID
	watchedChannels  sync.Map
	writeLock        sync.Mutex
	lockToMutexMap   map[string]*v3Concurrency.Mutex
	lockToSessionMap map[string]*v3Concurrency.Session
	lockToMutexLock  sync.Mutex
}

// NewEtcdClient returns a new client for the Etcd KV store
func NewEtcdClient(addr string, timeout int) (*EtcdClient, error) {
	duration := GetDuration(timeout)

	c, err := v3Client.New(v3Client.Config{
		Endpoints:   []string{addr},
		DialTimeout: duration,
	})
	if err != nil {
		log.Error(err)
		return nil, err
	}

	reservations := make(map[string]*v3Client.LeaseID)
	lockMutexMap := make(map[string]*v3Concurrency.Mutex)
	lockSessionMap := make(map[string]*v3Concurrency.Session)

	return &EtcdClient{ectdAPI: c, keyReservations: reservations, lockToMutexMap: lockMutexMap,
		lockToSessionMap: lockSessionMap}, nil
}

// IsConnectionUp returns whether the connection to the Etcd KV store is up.  If a timeout occurs then
// it is assumed the connection is down or unreachable.
func (c *EtcdClient) IsConnectionUp(timeout int) bool {
	// Let's try to get a non existent key.  If the connection is up then there will be no error returned.
	if _, err := c.Get("non-existent-key", timeout); err != nil {
		return false
	}
	return true
}

// List returns an array of key-value pairs with key as a prefix.  Timeout defines how long the function will
// wait for a response
func (c *EtcdClient) List(key string, timeout int, lock ...bool) (map[string]*KVPair, error) {
	duration := GetDuration(timeout)

	ctx, cancel := context.WithTimeout(context.Background(), duration)

	resp, err := c.ectdAPI.Get(ctx, key, v3Client.WithPrefix())
	cancel()
	if err != nil {
		log.Error(err)
		return nil, err
	}
	m := make(map[string]*KVPair)
	for _, ev := range resp.Kvs {
		m[string(ev.Key)] = NewKVPair(string(ev.Key), ev.Value, "", ev.Lease, ev.Version)
	}
	return m, nil
}

// Get returns a key-value pair for a given key. Timeout defines how long the function will
// wait for a response
func (c *EtcdClient) Get(key string, timeout int, lock ...bool) (*KVPair, error) {
	duration := GetDuration(timeout)

	ctx, cancel := context.WithTimeout(context.Background(), duration)

	resp, err := c.ectdAPI.Get(ctx, key)
	cancel()
	if err != nil {
		log.Error(err)
		return nil, err
	}
	for _, ev := range resp.Kvs {
		// Only one value is returned
		return NewKVPair(string(ev.Key), ev.Value, "", ev.Lease, ev.Version), nil
	}
	return nil, nil
}

// Put writes a key-value pair to the KV store.  Value can only be a string or []byte since the etcd API
// accepts only a string as a value for a put operation. Timeout defines how long the function will
// wait for a response
func (c *EtcdClient) Put(key string, value interface{}, timeout int, lock ...bool) error {

	// Validate that we can convert value to a string as etcd API expects a string
	var val string
	var er error
	if val, er = ToString(value); er != nil {
		return fmt.Errorf("unexpected-type-%T", value)
	}

	duration := GetDuration(timeout)

	ctx, cancel := context.WithTimeout(context.Background(), duration)

	c.writeLock.Lock()
	defer c.writeLock.Unlock()

	var err error
	// Check if there is already a lease for this key - if there is then use it, otherwise a PUT will make
	// that KV key permanent instead of automatically removing it after a lease expiration
	if leaseID, ok := c.keyReservations[key]; ok {
		_, err = c.ectdAPI.Put(ctx, key, val, v3Client.WithLease(*leaseID))
	} else {
		_, err = c.ectdAPI.Put(ctx, key, val)
	}
	cancel()
	if err != nil {
		switch err {
		case context.Canceled:
			log.Warnw("context-cancelled", log.Fields{"error": err})
		case context.DeadlineExceeded:
			log.Warnw("context-deadline-exceeded", log.Fields{"error": err})
		case v3rpcTypes.ErrEmptyKey:
			log.Warnw("etcd-client-error", log.Fields{"error": err})
		default:
			log.Warnw("bad-endpoints", log.Fields{"error": err})
		}
		return err
	}
	return nil
}

// Delete removes a key from the KV store. Timeout defines how long the function will
// wait for a response
func (c *EtcdClient) Delete(key string, timeout int, lock ...bool) error {

	duration := GetDuration(timeout)

	ctx, cancel := context.WithTimeout(context.Background(), duration)

	defer cancel()

	c.writeLock.Lock()
	defer c.writeLock.Unlock()

	// delete the key
	if _, err := c.ectdAPI.Delete(ctx, key); err != nil {
		log.Errorw("failed-to-delete-key", log.Fields{"key": key, "error": err})
		return err
	}
	log.Debugw("key(s)-deleted", log.Fields{"key": key})
	return nil
}

// Reserve is invoked to acquire a key and set it to a given value. Value can only be a string or []byte since
// the etcd API accepts only a string.  Timeout defines how long the function will wait for a response.  TTL
// defines how long that reservation is valid.  When TTL expires the key is unreserved by the KV store itself.
// If the key is acquired then the value returned will be the value passed in.  If the key is already acquired
// then the value assigned to that key will be returned.
func (c *EtcdClient) Reserve(key string, value interface{}, ttl int64) (interface{}, error) {
	// Validate that we can convert value to a string as etcd API expects a string
	var val string
	var er error
	if val, er = ToString(value); er != nil {
		return nil, fmt.Errorf("unexpected-type%T", value)
	}

	// Create a lease
	resp, err := c.ectdAPI.Grant(context.Background(), ttl)
	if err != nil {
		log.Error(err)
		return nil, err
	}
	// Register the lease id
	c.writeLock.Lock()
	c.keyReservations[key] = &resp.ID
	c.writeLock.Unlock()

	// Revoke lease if reservation is not successful
	reservationSuccessful := false
	defer func() {
		if !reservationSuccessful {
			if err = c.ReleaseReservation(key); err != nil {
				log.Error("cannot-release-lease")
			}
		}
	}()

	// Try to grap the Key with the above lease
	c.ectdAPI.Txn(context.Background())
	txn := c.ectdAPI.Txn(context.Background())
	txn = txn.If(v3Client.Compare(v3Client.Version(key), "=", 0))
	txn = txn.Then(v3Client.OpPut(key, val, v3Client.WithLease(resp.ID)))
	txn = txn.Else(v3Client.OpGet(key))
	result, er := txn.Commit()
	if er != nil {
		return nil, er
	}

	if !result.Succeeded {
		// Verify whether we are already the owner of that Key
		if len(result.Responses) > 0 &&
			len(result.Responses[0].GetResponseRange().Kvs) > 0 {
			kv := result.Responses[0].GetResponseRange().Kvs[0]
			if string(kv.Value) == val {
				reservationSuccessful = true
				return value, nil
			}
			return kv.Value, nil
		}
	} else {
		// Read the Key to ensure this is our Key
		m, err := c.Get(key, defaultKVGetTimeout, false)
		if err != nil {
			return nil, err
		}
		if m != nil {
			if m.Key == key && isEqual(m.Value, value) {
				// My reservation is successful - register it.  For now, support is only for 1 reservation per key
				// per session.
				reservationSuccessful = true
				return value, nil
			}
			// My reservation has failed.  Return the owner of that key
			return m.Value, nil
		}
	}
	return nil, nil
}

// ReleaseAllReservations releases all key reservations previously made (using Reserve API)
func (c *EtcdClient) ReleaseAllReservations() error {
	c.writeLock.Lock()
	defer c.writeLock.Unlock()
	for key, leaseID := range c.keyReservations {
		_, err := c.ectdAPI.Revoke(context.Background(), *leaseID)
		if err != nil {
			log.Errorw("cannot-release-reservation", log.Fields{"key": key, "error": err})
			return err
		}
		delete(c.keyReservations, key)
	}
	return nil
}

// ReleaseReservation releases reservation for a specific key.
func (c *EtcdClient) ReleaseReservation(key string) error {
	// Get the leaseid using the key
	log.Debugw("Release-reservation", log.Fields{"key": key})
	var ok bool
	var leaseID *v3Client.LeaseID
	c.writeLock.Lock()
	defer c.writeLock.Unlock()
	if leaseID, ok = c.keyReservations[key]; !ok {
		return nil
	}
	if leaseID != nil {
		_, err := c.ectdAPI.Revoke(context.Background(), *leaseID)
		if err != nil {
			log.Error(err)
			return err
		}
		delete(c.keyReservations, key)
	}
	return nil
}

// RenewReservation renews a reservation.  A reservation will go stale after the specified TTL (Time To Live)
// period specified when reserving the key
func (c *EtcdClient) RenewReservation(key string) error {
	// Get the leaseid using the key
	var ok bool
	var leaseID *v3Client.LeaseID
	c.writeLock.Lock()
	defer c.writeLock.Unlock()
	if leaseID, ok = c.keyReservations[key]; !ok {
		return errors.New("key-not-reserved")
	}

	if leaseID != nil {
		_, err := c.ectdAPI.KeepAliveOnce(context.Background(), *leaseID)
		if err != nil {
			log.Errorw("lease-may-have-expired", log.Fields{"error": err})
			return err
		}
	} else {
		return errors.New("lease-expired")
	}
	return nil
}

// Watch provides the watch capability on a given key.  It returns a channel onto which the callee needs to
// listen to receive Events.
func (c *EtcdClient) Watch(key string) chan *Event {
	w := v3Client.NewWatcher(c.ectdAPI)
	ctx, cancel := context.WithCancel(context.Background())
	channel := w.Watch(ctx, key)

	// Create a new channel
	ch := make(chan *Event, maxClientChannelBufferSize)

	// Keep track of the created channels so they can be closed when required
	channelMap := make(map[chan *Event]v3Client.Watcher)
	channelMap[ch] = w

	channelMaps := c.addChannelMap(key, channelMap)

	// Changing the log field (from channelMaps) as the underlying logger cannot format the map of channels into a
	// json format.
	log.Debugw("watched-channels", log.Fields{"len": len(channelMaps)})
	// Launch a go routine to listen for updates
	go c.listenForKeyChange(channel, ch, cancel)

	return ch

}

func (c *EtcdClient) addChannelMap(key string, channelMap map[chan *Event]v3Client.Watcher) []map[chan *Event]v3Client.Watcher {
	var channels interface{}
	var exists bool

	if channels, exists = c.watchedChannels.Load(key); exists {
		channels = append(channels.([]map[chan *Event]v3Client.Watcher), channelMap)
	} else {
		channels = []map[chan *Event]v3Client.Watcher{channelMap}
	}
	c.watchedChannels.Store(key, channels)

	return channels.([]map[chan *Event]v3Client.Watcher)
}

func (c *EtcdClient) removeChannelMap(key string, pos int) []map[chan *Event]v3Client.Watcher {
	var channels interface{}
	var exists bool

	if channels, exists = c.watchedChannels.Load(key); exists {
		channels = append(channels.([]map[chan *Event]v3Client.Watcher)[:pos], channels.([]map[chan *Event]v3Client.Watcher)[pos+1:]...)
		c.watchedChannels.Store(key, channels)
	}

	return channels.([]map[chan *Event]v3Client.Watcher)
}

func (c *EtcdClient) getChannelMaps(key string) ([]map[chan *Event]v3Client.Watcher, bool) {
	var channels interface{}
	var exists bool

	channels, exists = c.watchedChannels.Load(key)

	if channels == nil {
		return nil, exists
	}

	return channels.([]map[chan *Event]v3Client.Watcher), exists
}

// CloseWatch closes a specific watch. Both the key and the channel are required when closing a watch as there
// may be multiple listeners on the same key.  The previously created channel serves as a key
func (c *EtcdClient) CloseWatch(key string, ch chan *Event) {
	// Get the array of channels mapping
	var watchedChannels []map[chan *Event]v3Client.Watcher
	var ok bool
	c.writeLock.Lock()
	defer c.writeLock.Unlock()

	if watchedChannels, ok = c.getChannelMaps(key); !ok {
		log.Warnw("key-has-no-watched-channels", log.Fields{"key": key})
		return
	}
	// Look for the channels
	var pos = -1
	for i, chMap := range watchedChannels {
		if t, ok := chMap[ch]; ok {
			log.Debug("channel-found")
			// Close the etcd watcher before the client channel.  This should close the etcd channel as well
			if err := t.Close(); err != nil {
				log.Errorw("watcher-cannot-be-closed", log.Fields{"key": key, "error": err})
			}
			pos = i
			break
		}
	}

	channelMaps, _ := c.getChannelMaps(key)
	// Remove that entry if present
	if pos >= 0 {
		channelMaps = c.removeChannelMap(key, pos)
	}
	log.Infow("watcher-channel-exiting", log.Fields{"key": key, "channel": channelMaps})
}

func (c *EtcdClient) listenForKeyChange(channel v3Client.WatchChan, ch chan<- *Event, cancel context.CancelFunc) {
	log.Debug("start-listening-on-channel ...")
	defer cancel()
	defer close(ch)
	for resp := range channel {
		for _, ev := range resp.Events {
			ch <- NewEvent(getEventType(ev), ev.Kv.Key, ev.Kv.Value, ev.Kv.Version)
		}
	}
	log.Debug("stop-listening-on-channel ...")
}

func getEventType(event *v3Client.Event) int {
	switch event.Type {
	case v3Client.EventTypePut:
		return PUT
	case v3Client.EventTypeDelete:
		return DELETE
	}
	return UNKNOWN
}

// Close closes the KV store client
func (c *EtcdClient) Close() {
	c.writeLock.Lock()
	defer c.writeLock.Unlock()
	if err := c.ectdAPI.Close(); err != nil {
		log.Errorw("error-closing-client", log.Fields{"error": err})
	}
}

func (c *EtcdClient) addLockName(lockName string, lock *v3Concurrency.Mutex, session *v3Concurrency.Session) {
	c.lockToMutexLock.Lock()
	defer c.lockToMutexLock.Unlock()
	c.lockToMutexMap[lockName] = lock
	c.lockToSessionMap[lockName] = session
}

func (c *EtcdClient) deleteLockName(lockName string) {
	c.lockToMutexLock.Lock()
	defer c.lockToMutexLock.Unlock()
	delete(c.lockToMutexMap, lockName)
	delete(c.lockToSessionMap, lockName)
}

func (c *EtcdClient) getLock(lockName string) (*v3Concurrency.Mutex, *v3Concurrency.Session) {
	c.lockToMutexLock.Lock()
	defer c.lockToMutexLock.Unlock()
	var lock *v3Concurrency.Mutex
	var session *v3Concurrency.Session
	if l, exist := c.lockToMutexMap[lockName]; exist {
		lock = l
	}
	if s, exist := c.lockToSessionMap[lockName]; exist {
		session = s
	}
	return lock, session
}

func (c *EtcdClient) AcquireLock(lockName string, timeout int) error {
	duration := GetDuration(timeout)
	ctx, cancel := context.WithTimeout(context.Background(), duration)
	defer cancel()
	session, _ := v3Concurrency.NewSession(c.ectdAPI, v3Concurrency.WithContext(ctx))
	mu := v3Concurrency.NewMutex(session, "/devicelock_"+lockName)
	if err := mu.Lock(context.Background()); err != nil {
		cancel()
		return err
	}
	c.addLockName(lockName, mu, session)
	return nil
}

func (c *EtcdClient) ReleaseLock(lockName string) error {
	lock, session := c.getLock(lockName)
	var err error
	if lock != nil {
		if e := lock.Unlock(context.Background()); e != nil {
			err = e
		}
	}
	if session != nil {
		if e := session.Close(); e != nil {
			err = e
		}
	}
	c.deleteLockName(lockName)

	return err
}
