// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

package client

import (
	
	
	

	
)

const (
	maxRtxInterval time.Duration = 1600 * time.Millisecond
)

// TransactionResult is a bag of result values of a transaction.
type TransactionResult struct {
	Msg     *stun.Message
	From    net.Addr
	Retries int
	Err     error
}

// TransactionConfig is a set of config params used by NewTransaction.
type TransactionConfig struct {
	Key          string
	Raw          []byte
	To           net.Addr
	Interval     time.Duration
	IgnoreResult bool // True to throw away the result of this transaction (it will not be readable using WaitForResult)
}

// Transaction represents a transaction.
type Transaction struct {
	Key      string                 // Read-only
	Raw      []byte                 // Read-only
	To       net.Addr               // Read-only
	nRtx     int                    // Modified only by the timer thread
	interval time.Duration          // Modified only by the timer thread
	timer    *time.Timer            // Thread-safe, set only by the creator, and stopper
	resultCh chan TransactionResult // Thread-safe
	mutex    sync.RWMutex
}

// NewTransaction creates a new instance of Transaction.
func ( *TransactionConfig) *Transaction {
	var  chan TransactionResult
	if !.IgnoreResult {
		 = make(chan TransactionResult)
	}

	return &Transaction{
		Key:      .Key,      // Read-only
		Raw:      .Raw,      // Read-only
		To:       .To,       // Read-only
		interval: .Interval, // Modified only by the timer thread
		resultCh: ,        // Thread-safe
	}
}

// StartRtxTimer starts the transaction timer.
func ( *Transaction) ( func( string,  int)) {
	.mutex.Lock()
	defer .mutex.Unlock()

	.timer = time.AfterFunc(.interval, func() {
		.mutex.Lock()
		.nRtx++
		 := .nRtx
		.interval *= 2
		if .interval > maxRtxInterval {
			.interval = maxRtxInterval
		}
		.mutex.Unlock()
		(.Key, )
	})
}

// StopRtxTimer stop the transaction timer.
func ( *Transaction) () {
	.mutex.Lock()
	defer .mutex.Unlock()

	if .timer != nil {
		.timer.Stop()
	}
}

// WriteResult writes the result to the result channel.
func ( *Transaction) ( TransactionResult) bool {
	if .resultCh == nil {
		return false
	}

	.resultCh <- 

	return true
}

// WaitForResult waits for the transaction result.
func ( *Transaction) () TransactionResult {
	if .resultCh == nil {
		return TransactionResult{
			Err: errWaitForResultOnNonResultTransaction,
		}
	}

	,  := <-.resultCh
	if ! {
		.Err = errTransactionClosed
	}

	return 
}

// Close closes the transaction.
func ( *Transaction) () {
	if .resultCh != nil {
		close(.resultCh)
	}
}

// Retries returns the number of retransmission it has made.
func ( *Transaction) () int {
	.mutex.RLock()
	defer .mutex.RUnlock()

	return .nRtx
}

// TransactionMap is a thread-safe transaction map.
type TransactionMap struct {
	trMap map[string]*Transaction
	mutex sync.RWMutex
}

// NewTransactionMap create a new instance of the transaction map.
func () *TransactionMap {
	return &TransactionMap{
		trMap: map[string]*Transaction{},
	}
}

// Insert inserts a transaction to the map.
func ( *TransactionMap) ( string,  *Transaction) bool {
	.mutex.Lock()
	defer .mutex.Unlock()

	.trMap[] = 

	return true
}

// Find looks up a transaction by its key.
func ( *TransactionMap) ( string) (*Transaction, bool) {
	.mutex.RLock()
	defer .mutex.RUnlock()

	,  := .trMap[]

	return , 
}

// Delete deletes a transaction by its key.
func ( *TransactionMap) ( string) {
	.mutex.Lock()
	defer .mutex.Unlock()

	delete(.trMap, )
}

// CloseAndDeleteAll closes and deletes all transactions.
func ( *TransactionMap) () {
	.mutex.Lock()
	defer .mutex.Unlock()

	for ,  := range .trMap {
		.Close()
		delete(.trMap, )
	}
}

// Size returns the length of the transaction map.
func ( *TransactionMap) () int {
	.mutex.RLock()
	defer .mutex.RUnlock()

	return len(.trMap)
}