// Copyright 2021 ChainSafe Systems (ON)
// SPDX-License-Identifier: LGPL-3.0-only

package transaction

import (
	"sync"

	"github.com/ChainSafe/gossamer/lib/common"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
)

var transactionPoolGauge = promauto.NewGauge(prometheus.GaugeOpts{
	Namespace: "gossamer_state_transaction",
	Name:      "pool_total",
	Help:      "total number of transactions in ready pool",
})

// Pool represents the transaction pool
type Pool struct {
	transactions map[common.Hash]*ValidTransaction
	mu           sync.RWMutex
}

// NewPool returns a new empty Pool
func NewPool() *Pool {
	return &Pool{
		transactions: make(map[common.Hash]*ValidTransaction),
	}
}

// Get returns a pointer to ValidTransaction or nil given an extinsic hash
func (p *Pool) Get(extHash common.Hash) *ValidTransaction {
	p.mu.RLock()
	defer p.mu.RUnlock()

	return p.transactions[extHash]
}

// Transactions returns all the transactions in the pool
func (p *Pool) Transactions() []*ValidTransaction {
	txs := make([]*ValidTransaction, len(p.transactions))
	i := 0

	p.mu.RLock()
	defer p.mu.RUnlock()

	for _, tx := range p.transactions {
		txs[i] = tx
		i++
	}
	return txs
}

// Insert inserts a transaction into the pool
func (p *Pool) Insert(tx *ValidTransaction) common.Hash {
	hash := tx.Extrinsic.Hash()
	p.mu.Lock()
	defer p.mu.Unlock()
	p.transactions[hash] = tx
	transactionPoolGauge.Set(float64(len(p.transactions)))
	return hash
}

// Remove removes a transaction from the pool
func (p *Pool) Remove(hash common.Hash) {
	p.mu.Lock()
	defer p.mu.Unlock()
	delete(p.transactions, hash)
	transactionPoolGauge.Set(float64(len(p.transactions)))
}

// Len return the current length of the pool
func (p *Pool) Len() int {
	p.mu.Lock()
	defer p.mu.Unlock()

	return len(p.transactions)
}
