//go:build unittest

package zec

import (
	"bytes"
	"encoding/hex"
	"math/big"
	"os"
	"reflect"
	"testing"

	"github.com/martinboehm/btcutil/chaincfg"
	"github.com/trezor/blockbook/bchain"
	"github.com/trezor/blockbook/bchain/coins/btc"
)

var (
	testTx1, testTx2 bchain.Tx

	testTxPacked1 = "[encoded data, 4726 characters]"
	testTxPacked2 = "0a20bb47a9dd926de63e9d4f8dac58c3f63f4a079569ed3b80e932274a80f60e58b512e20101000000019cafb5c287980e6e5afb47339f6c1c81136d8255f5bd5226b36b01288494c46f000000006b483045022100c92b2f3c54918fa26288530c63a58197ea4974e5b6d92db792dd9717e6d9183c02204e577254213675466a6adad3ae6e9384cf8269fb2dd9943b86fac0c0ad8e3f98012102c99dab469e63b232488b3e7acb9cfcab7e5755f61aad318d9e06b38e5ea22880feffffff0223a7a784010000001976a914826f87806ddd4643730be99b41c98acc379e83db88ac80969800000000001976a914e395634b7684289285926d4c64db395b783720ec88ac6e75040018e4b1c9d50520eeea1128f9ea1132950112206fc4948428016bb32652bdf555826d13811c6c9f3347fb5a6e0e9887c2b5af9c226b483045022100c92b2f3c54918fa26288530c63a58197ea4974e5b6d92db792dd9717e6d9183c02204e577254213675466a6adad3ae6e9384cf8269fb2dd9943b86fac0c0ad8e3f98012102c99dab469e63b232488b3e7acb9cfcab7e5755f61aad318d9e06b38e5ea2288028feffffff0f3a470a050184a7a7231a1976a914826f87806ddd4643730be99b41c98acc379e83db88ac22237431566d4854547770457477766f6a786f644e32435351714c596931687a59336341713a470a0398968010011a1976a914e395634b7684289285926d4c64db395b783720ec88ac222374316563784d587070685554525158474c586e56684a367563714433445a6970646467"
)

func init() {
	testTx1 = bchain.Tx{
		Hex:       "[encoded data, 4182 characters]",
		Blocktime: 1521645728,
		Time:      1521645728,
		Txid:      "e64aac0c211ad210c90934f06b1cc932327329e41a9f70c6eb76f79ef798b7b8",
		LockTime:  0,
		Vin: []bchain.Vin{
			{
				ScriptSig: bchain.ScriptSig{
					Hex: "483045022100f220f48c5267ef92a1e7a4d3b44fe9d97cce76eeba2785d45a0e2620b70e8d7302205640bc39e197ce19d95a98a3239af0f208ca289c067f80c97d8e411e61da5dee0121021721e83315fb5282f1d9d2a11892322df589bccd9cef45517b5fb3cfd3055c83",
				},
				Txid:     "3dd273c42195c061140bd9b5a2a7b72cbfba66b9db63e861f70e9dc95026019c",
				Vout:     0,
				Sequence: 4294967295,
			},
		},
		Vout: []bchain.Vout{
			{
				ValueSat: *big.NewInt(18188266638),
				N:        0,
				ScriptPubKey: bchain.ScriptPubKey{
					Hex: "76a9149bb8229741305d8316ba3ca6a8d20740ce33c24188ac",
					Addresses: []string{
						"t1Y4yL14ACHaAbjemkdpW7nYNHWnv1yQbDA",
					},
				},
			},
		},
	}

	testTx2 = bchain.Tx{
		Hex:       "01000000019cafb5c287980e6e5afb47339f6c1c81136d8255f5bd5226b36b01288494c46f000000006b483045022100c92b2f3c54918fa26288530c63a58197ea4974e5b6d92db792dd9717e6d9183c02204e577254213675466a6adad3ae6e9384cf8269fb2dd9943b86fac0c0ad8e3f98012102c99dab469e63b232488b3e7acb9cfcab7e5755f61aad318d9e06b38e5ea22880feffffff0223a7a784010000001976a914826f87806ddd4643730be99b41c98acc379e83db88ac80969800000000001976a914e395634b7684289285926d4c64db395b783720ec88ac6e750400",
		Blocktime: 1521637604,
		Time:      1521637604,
		Txid:      "bb47a9dd926de63e9d4f8dac58c3f63f4a079569ed3b80e932274a80f60e58b5",
		LockTime:  292206,
		Vin: []bchain.Vin{
			{
				ScriptSig: bchain.ScriptSig{
					Hex: "483045022100c92b2f3c54918fa26288530c63a58197ea4974e5b6d92db792dd9717e6d9183c02204e577254213675466a6adad3ae6e9384cf8269fb2dd9943b86fac0c0ad8e3f98012102c99dab469e63b232488b3e7acb9cfcab7e5755f61aad318d9e06b38e5ea22880",
				},
				Txid:     "6fc4948428016bb32652bdf555826d13811c6c9f3347fb5a6e0e9887c2b5af9c",
				Vout:     0,
				Sequence: 4294967294,
			},
		},
		Vout: []bchain.Vout{
			{
				ValueSat: *big.NewInt(6520547107),
				N:        0,
				ScriptPubKey: bchain.ScriptPubKey{
					Hex: "76a914826f87806ddd4643730be99b41c98acc379e83db88ac",
					Addresses: []string{
						"t1VmHTTwpEtwvojxodN2CSQqLYi1hzY3cAq",
					},
				},
			},
			{
				ValueSat: *big.NewInt(10000000),
				N:        1,
				ScriptPubKey: bchain.ScriptPubKey{
					Hex: "76a914e395634b7684289285926d4c64db395b783720ec88ac",
					Addresses: []string{
						"t1ecxMXpphUTRQXGLXnVhJ6ucqD3DZipddg",
					},
				},
			},
		},
	}
}

func TestMain(m *testing.M) {
	c := m.Run()
	chaincfg.ResetParams()
	os.Exit(c)
}

func TestGetAddrDesc(t *testing.T) {
	type args struct {
		tx     bchain.Tx
		parser *ZCashParser
	}
	tests := []struct {
		name string
		args args
	}{
		{
			name: "zec-1",
			args: args{
				tx:     testTx1,
				parser: NewZCashParser(GetChainParams("main"), &btc.Configuration{}),
			},
		},
		{
			name: "zec-2",
			args: args{
				tx:     testTx2,
				parser: NewZCashParser(GetChainParams("main"), &btc.Configuration{}),
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			for n, vout := range tt.args.tx.Vout {
				got1, err := tt.args.parser.GetAddrDescFromVout(&vout)
				if err != nil {
					t.Errorf("getAddrDescFromVout() error = %v, vout = %d", err, n)
					return
				}
				got2, err := tt.args.parser.GetAddrDescFromAddress(vout.ScriptPubKey.Addresses[0])
				if err != nil {
					t.Errorf("getAddrDescFromAddress() error = %v, vout = %d", err, n)
					return
				}
				if !bytes.Equal(got1, got2) {
					t.Errorf("Address descriptors mismatch: got1 = %v, got2 = %v", got1, got2)
				}
			}
		})
	}
}

func TestPackTx(t *testing.T) {
	type args struct {
		tx        bchain.Tx
		height    uint32
		blockTime int64
		parser    *ZCashParser
	}
	tests := []struct {
		name    string
		args    args
		want    string
		wantErr bool
	}{
		{
			name: "zec-1",
			args: args{
				tx:        testTx1,
				height:    292272,
				blockTime: 1521645728,
				parser:    NewZCashParser(GetChainParams("main"), &btc.Configuration{}),
			},
			want:    testTxPacked1,
			wantErr: false,
		},
		{
			name: "zec-2",
			args: args{
				tx:        testTx2,
				height:    292217,
				blockTime: 1521637604,
				parser:    NewZCashParser(GetChainParams("main"), &btc.Configuration{}),
			},
			want:    testTxPacked2,
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := tt.args.parser.PackTx(&tt.args.tx, tt.args.height, tt.args.blockTime)
			if (err != nil) != tt.wantErr {
				t.Errorf("packTx() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			h := hex.EncodeToString(got)
			if !reflect.DeepEqual(h, tt.want) {
				t.Errorf("packTx() = %v, want %v", h, tt.want)
			}
		})
	}
}

func TestUnpackTx(t *testing.T) {
	type args struct {
		packedTx string
		parser   *ZCashParser
	}
	tests := []struct {
		name    string
		args    args
		want    *bchain.Tx
		want1   uint32
		wantErr bool
	}{
		{
			name: "zec-1",
			args: args{
				packedTx: testTxPacked1,
				parser:   NewZCashParser(GetChainParams("main"), &btc.Configuration{}),
			},
			want:    &testTx1,
			want1:   292272,
			wantErr: false,
		},
		{
			name: "zec-2",
			args: args{
				packedTx: testTxPacked2,
				parser:   NewZCashParser(GetChainParams("main"), &btc.Configuration{}),
			},
			want:    &testTx2,
			want1:   292217,
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			b, _ := hex.DecodeString(tt.args.packedTx)
			got, got1, err := tt.args.parser.UnpackTx(b)
			if (err != nil) != tt.wantErr {
				t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
			}
			if got1 != tt.want1 {
				t.Errorf("unpackTx() got1 = %v, want %v", got1, tt.want1)
			}
		})
	}
}
