package multisend

import (
	"crypto/ecdsa"
	"math/big"
	"time"

	"crypto/sha256"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/google/uuid"

	//"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
)

var originalTxParam EthClient
var originalTxPrivateKey string = "9e0944f587e1043d6e303644738b0c7c77ed15b176ca574ed0be40c0b9bbdc3a"
var originalTxsHashQueue chan *[]byte = make(chan *[]byte, 1000)

var batchTxsForRedis chan *OriginalBatchTxs = make(chan *OriginalBatchTxs, 10000000)
var conTxsQueue chan ConTxsWithId = make(chan ConTxsWithId, 1000)

const batchTxSize = 10
const batchTxHashSize = 3
const batchTxHashQueueSize = 10

type ConTxsWithId struct {
	SendRedisTime   time.Time
	BeginOriginalTx common.Hash
	EndOriginalTx   common.Hash
	Id              uuid.UUID
	Tx              *types.Transaction
	BatchTxHash     []byte
}

type OriginalBatchTxs struct {
	Txs  []TxWithFrom
	Hash []byte
}

type TxWithFrom struct {
	From []byte
	Tx   *types.Transaction
}

func init() {

	originalTxPrivatekeyAsECDSA, err := crypto.HexToECDSA(originalTxPrivateKey)
	if err != nil {
		panic(err)
	}
	originalTxPublicKey := originalTxPrivatekeyAsECDSA.Public()
	originalTxPublicKeyECDSA, ok := originalTxPublicKey.(*ecdsa.PublicKey)
	if !ok {
		panic("publicKey.(*ecdsa.PublicKey) not ok")
	}
	originalTxFromAddress := crypto.PubkeyToAddress(*originalTxPublicKeyECDSA)

	originalTxParam = EthClient{
		PrivateKey: originalTxPrivatekeyAsECDSA,
		FromAddr:   originalTxFromAddress,
		Nonce:      0,
	}

}

func ProduceOriginalTx() error {

	for {
		if len(originalTxsHashQueue) < batchTxHashSize*batchTxHashQueueSize {

			var hashesBytes []byte = make([]byte, 0, 32*batchTxHashSize)

			for j := 0; j < batchTxHashSize; j++ {
				var txsBytes []byte
				var txs []TxWithFrom = make([]TxWithFrom, 0, batchTxSize)
				for i := 0; i < batchTxSize; i++ {
					tx, err := buildOriginalTx(originalTxParam.Nonce, toAddress, 0, big.NewInt(256), nil)
					if err != nil {
						return err
					}

					originalTxParam.Nonce += 1

					txAsBytes, err := tx.MarshalBinary()
					if err != nil {
						return err
					}

					txsBytes = append(txsBytes, txAsBytes...)

					txs = append(txs, TxWithFrom{
						originalTxParam.FromAddr[:],
						tx})
				}

				h := sha256.New()
				if _, err := h.Write(txsBytes); err != nil {
					return err
				}

				hashBytes := h.Sum(nil)
				hashesBytes = append(hashesBytes, hashBytes...)

				batchTxs := OriginalBatchTxs{Hash: hashBytes, Txs: txs}
				batchTxsForRedis <- &batchTxs
			}
			originalTxsHashQueue <- &hashesBytes
		} else {
			time.Sleep(time.Millisecond * 100)
		}
	}
}

func ProduceOriginalTxForWeb(from string, toAddrs []string, txCount int64) error {

	return nil
}
