package common

import (
	"math/big"

	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
)

type TransferTable struct {
	txs map[string]map[string]*TransferTx
}

type TransferTx struct {
	From, To user.ID

	Amount *big.Int
}

func NewTransferTable() *TransferTable {
	return &TransferTable{
		txs: make(map[string]map[string]*TransferTx),
	}
}

func (t *TransferTable) Transfer(tx *TransferTx) {
	if tx.From.Equals(tx.To) {
		return
	}

	from, to := tx.From.EncodeToString(), tx.To.EncodeToString()

	m, ok := t.txs[from]
	if !ok {
		if m, ok = t.txs[to]; ok {
			to = from // ignore `From = To` swap because `From` doesn't require
			tx.Amount.Neg(tx.Amount)
		} else {
			m = make(map[string]*TransferTx, 1)
			t.txs[from] = m
		}
	}

	tgt, ok := m[to]
	if !ok {
		m[to] = tx
		return
	}

	tgt.Amount.Add(tgt.Amount, tx.Amount)
}

func (t *TransferTable) Iterate(f func(*TransferTx)) {
	for _, m := range t.txs {
		for _, tx := range m {
			f(tx)
		}
	}
}

func TransferAssets(e Exchanger, t *TransferTable, details []byte) {
	t.Iterate(func(tx *TransferTx) {
		sign := tx.Amount.Sign()
		if sign == 0 {
			return
		}

		if sign < 0 {
			tx.From, tx.To = tx.To, tx.From
			tx.Amount.Neg(tx.Amount)
		}

		e.Transfer(tx.From, tx.To, tx.Amount, details)
	})
}