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

package event

import (
	"time"

	"github.com/ChainSafe/gossamer/internal/client/network"
	"github.com/ChainSafe/gossamer/internal/client/network/role"
	"github.com/ChainSafe/gossamer/internal/client/network/types/kad"
	peerid "github.com/ChainSafe/gossamer/internal/client/network/types/peer-id"
)

// DHTEvent is an event generated by DHT as a response to get/put value requests.
type DHTEvent interface {
	isDHTEvent()
}

// DHTEventValueFound mean the value was found.
type DHTEventValueFound kad.PeerRecord

// DHTEventValueNotFound means the requested record has not been found in the DHT.
type DHTEventValueNotFound kad.Key

// DHTEventValuePut means the record has been successfully inserted into the DHT.
type DHTEventValuePut kad.Key

// DHTEventValuePutFailed means an error has occurred while putting a record into the DHT.
type DHTEventValuePutFailed kad.Key

// DHTEventStartProvidingFailed means an error occurred while registering as a content provider on the DHT.
type DHTEventStartProvidingFailed kad.Key

// DHTEventPutRecordRequest means the DHT received a put record request.
type DHTEventPutRecordRequest struct {
	Key       kad.Key
	Value     []byte
	Publisher *peerid.PeerID
	Expires   time.Time
}

// DHTEventProvidersFound contains the providers for [kad.Key] that were found.
type DHTEventProvidersFound struct {
	Key       kad.Key
	Providers []peerid.PeerID
}

// DHTEventProvidersNotFound means the providers for [kad.Key] were not found.
type DHTEventProvidersNotFound kad.Key

func (DHTEventValueFound) isDHTEvent()           {}
func (DHTEventValueNotFound) isDHTEvent()        {}
func (DHTEventValuePut) isDHTEvent()             {}
func (DHTEventValuePutFailed) isDHTEvent()       {}
func (DHTEventStartProvidingFailed) isDHTEvent() {}
func (DHTEventPutRecordRequest) isDHTEvent()     {}
func (DHTEventProvidersFound) isDHTEvent()       {}

// Event is an event generated by the networking layer.
type Event interface {
	isEvent()
}

// EventDHT is an event generated by a DHT.
type EventDHT struct {
	DHTEvent
}

// EventNotificationStreamOpened represents an opened a substream with the given node with the given notifications
// protocol. The protocol is always one of the notification protocols that have been registered.
type EventNotificationStreamOpened struct {
	// Node we opened the substream with.
	Remote peerid.PeerID
	// The concerned protocol. Each protocol uses a different substream.
	Protocol network.ProtocolName
	// If the negotiation didn't use the main name of the protocol, then this field contains which name has actually
	// been used.
	NegotiatedFallback *network.ProtocolName
	// Role of the remote.
	Role role.ObservedRole
	// Received handshake.
	ReceivedHandshake []byte
}

// Closed a substream with the given node. Always matches a corresponding previous
// [EventNotificationStreamOpened] message.
type EventNotificationStreamClosed struct {
	// Node we closed the substream with.
	Remote peerid.PeerID
	// The concerned protocol. Each protocol uses a different substream.
	Protocol network.ProtocolName
}

// Received one or more messages from the given node using the given protocol.
type EventNotificationsReceived struct {
	// Node we received the message from.
	Remote peerid.PeerID
	// Concerned protocol and associated message.
	Messages []struct {
		Protocol network.ProtocolName
		Message  []byte
	}
}

func (EventDHT) isEvent()                      {}
func (EventNotificationStreamOpened) isEvent() {}
func (EventNotificationStreamClosed) isEvent() {}
func (EventNotificationsReceived) isEvent()    {}
