package mempool

import (
	"errors"

	abci "github.com/cometbft/cometbft/abci/types"
	"github.com/cometbft/cometbft/libs/service"
	"github.com/cometbft/cometbft/p2p"
	"github.com/cometbft/cometbft/types"
)

// NopMempool is a mempool that does nothing.
//
// The ABCI app is responsible for storing, disseminating, and proposing transactions.
// See [ADR-111](../docs/architecture/adr-111-nop-mempool.md).
type NopMempool struct{}

// errNotAllowed indicates that the operation is not allowed with `nop` mempool.
var errNotAllowed = errors.New("not allowed with `nop` mempool")

var _ Mempool = &NopMempool{}

// CheckTx always returns an error.
func (*NopMempool) CheckTx(types.Tx, func(*abci.ResponseCheckTx), TxInfo) error {
	return errNotAllowed
}

// RemoveTxByKey always returns an error.
func (*NopMempool) RemoveTxByKey(types.TxKey) error { return errNotAllowed }

// ReapMaxBytesMaxGas always returns nil.
func (*NopMempool) ReapMaxBytesMaxGas(int64, int64) []*types.CachedTx { return nil }

// ReapMaxTxs always returns nil.
func (*NopMempool) ReapMaxTxs(int) []*types.CachedTx { return nil }

// Lock does nothing.
func (*NopMempool) Lock() {}

// Unlock does nothing.
func (*NopMempool) Unlock() {}

// Update does nothing.
func (*NopMempool) Update(
	int64,
	[]*types.CachedTx,
	[]*abci.ExecTxResult,
	PreCheckFunc,
	PostCheckFunc,
) error {
	return nil
}

// FlushAppConn does nothing.
func (*NopMempool) FlushAppConn() error { return nil }

// Flush does nothing.
func (*NopMempool) Flush() {}

// TxsAvailable always returns nil.
func (*NopMempool) TxsAvailable() <-chan struct{} {
	return nil
}

// EnableTxsAvailable does nothing.
func (*NopMempool) EnableTxsAvailable() {}

// SetTxRemovedCallback does nothing.
func (*NopMempool) SetTxRemovedCallback(func(txKey types.TxKey)) {}

// Size always returns 0.
func (*NopMempool) Size() int { return 0 }

// SizeBytes always returns 0.
func (*NopMempool) SizeBytes() int64 { return 0 }

// GetTxByKey always returns nil.
func (*NopMempool) GetTxByKey(types.TxKey) (*types.CachedTx, bool) { return nil, false }

// WasRecentlyEvicted always returns false.
func (*NopMempool) WasRecentlyEvicted(types.TxKey) bool { return false }

// WasRecentlyRejected always returns false, zero and an empty string.
func (*NopMempool) WasRecentlyRejected(types.TxKey) (bool, uint32, string) { return false, 0, "" }

// NopMempoolReactor is a mempool reactor that does nothing.
type NopMempoolReactor struct {
	service.BaseService
}

// NewNopMempoolReactor returns a new `nop` reactor.
//
// To be used only in RPC.
func NewNopMempoolReactor() *NopMempoolReactor {
	return &NopMempoolReactor{*service.NewBaseService(nil, "NopMempoolReactor", nil)}
}

var _ p2p.Reactor = &NopMempoolReactor{}

// GetChannels always returns nil.
func (*NopMempoolReactor) GetChannels() []*p2p.ChannelDescriptor { return nil }

// AddPeer does nothing.
func (*NopMempoolReactor) AddPeer(p2p.Peer) {}

// InitPeer always returns nil.
func (*NopMempoolReactor) InitPeer(p2p.Peer) (p2p.Peer, error) { return nil, nil }

// RemovePeer does nothing.
func (*NopMempoolReactor) RemovePeer(p2p.Peer, interface{}) {}

// Receive does nothing.
func (*NopMempoolReactor) Receive(p2p.Envelope) {}

// SetSwitch does nothing.
func (*NopMempoolReactor) SetSwitch(*p2p.Switch) {}

// QueueUnprocessedEnvelope does nothing.
func (*NopMempoolReactor) QueueUnprocessedEnvelope(p2p.UnprocessedEnvelope) {}
