package irc

import (
	"sync"

	"github.com/ergochat/ergo/irc/utils"
)

// tracks ACCEPT relationships, i.e., `accepter` is willing to receive DMs from
// `accepted` despite some restriction (currently the only relevant restriction
// is that `accepter` is +R and `accepted` is not logged in)

type AcceptManager struct {
	sync.RWMutex

	// maps recipient -> whitelist of permitted senders:
	// this is what we actually check
	clientToAccepted map[*Client]utils.HashSet[*Client]
	// this is the reverse mapping, it's needed so we can
	// clean up the forward mapping during (*Client).destroy():
	clientToAccepters map[*Client]utils.HashSet[*Client]
}

func (am *AcceptManager) Initialize() {
	am.clientToAccepted = make(map[*Client]utils.HashSet[*Client])
	am.clientToAccepters = make(map[*Client]utils.HashSet[*Client])
}

func (am *AcceptManager) MaySendTo(sender, recipient *Client) (result bool) {
	am.RLock()
	defer am.RUnlock()
	return am.clientToAccepted[recipient].Has(sender)
}

func (am *AcceptManager) Accept(accepter, accepted *Client) {
	am.Lock()
	defer am.Unlock()

	var m utils.HashSet[*Client]

	m = am.clientToAccepted[accepter]
	if m == nil {
		m = make(utils.HashSet[*Client])
		am.clientToAccepted[accepter] = m
	}
	m.Add(accepted)

	m = am.clientToAccepters[accepted]
	if m == nil {
		m = make(utils.HashSet[*Client])
		am.clientToAccepters[accepted] = m
	}
	m.Add(accepter)
}

func (am *AcceptManager) Unaccept(accepter, accepted *Client) {
	am.Lock()
	defer am.Unlock()

	delete(am.clientToAccepted[accepter], accepted)
	delete(am.clientToAccepters[accepted], accepter)
}

func (am *AcceptManager) Remove(client *Client) {
	am.Lock()
	defer am.Unlock()

	for accepter := range am.clientToAccepters[client] {
		delete(am.clientToAccepted[accepter], client)
	}
	for accepted := range am.clientToAccepted[client] {
		delete(am.clientToAccepters[accepted], client)
	}
	delete(am.clientToAccepters, client)
	delete(am.clientToAccepted, client)
}