//go:build unittest

package liquid

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

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

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

func Test_GetAddrDescFromAddress(t *testing.T) {
	type args struct {
		address string
	}
	tests := []struct {
		name    string
		args    args
		want    string
		wantErr bool
	}{
		{
			name:    "P2PKH1",
			args:    args{address: "QHU1yszeZwVeuJosGJ4JDHuKaLRWmdEYDF"},
			want:    "76a914dd95db91e8f914cbd63bae8e307d54399f060cd688ac",
			wantErr: false,
		},
		{
			name:    "P2PKH2",
			args:    args{address: "PwogNb9zqhrwPneDqVp18GqcVuygsCvXkU"},
			want:    "76a91405eb4afe4615751cfb813a00846a8d9ef8a9a2e588ac",
			wantErr: false,
		},
		{
			name:    "P2SH1",
			args:    args{address: "GhWTZqLPHRK8KfuT6yo1wGisQzn4cXrbPP"},
			want:    "a9140394b3cf9a44782c10105b93962daa8dba304d7f87",
			wantErr: false,
		},
	}
	parser := NewLiquidParser(GetChainParams("main"), &btc.Configuration{})

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := parser.GetAddrDescFromAddress(tt.args.address)
			if (err != nil) != tt.wantErr {
				t.Errorf("GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			h := hex.EncodeToString(got)
			if !reflect.DeepEqual(h, tt.want) {
				t.Errorf("GetAddrDescFromAddress() = %v, want %v", h, tt.want)
			}
		})
	}
}

func Test_GetAddressesFromAddrDesc(t *testing.T) {
	type args struct {
		script string
	}
	tests := []struct {
		name    string
		args    args
		want    []string
		want2   bool
		wantErr bool
	}{
		{
			name:    "P2PKH1",
			args:    args{script: "76a914dd95db91e8f914cbd63bae8e307d54399f060cd688ac"},
			want:    []string{"QHU1yszeZwVeuJosGJ4JDHuKaLRWmdEYDF"},
			want2:   true,
			wantErr: false,
		},
		{
			name:    "P2PKH2",
			args:    args{script: "76a91405eb4afe4615751cfb813a00846a8d9ef8a9a2e588ac"},
			want:    []string{"PwogNb9zqhrwPneDqVp18GqcVuygsCvXkU"},
			want2:   true,
			wantErr: false,
		},
		{
			name:    "P2SH",
			args:    args{script: "a9140394b3cf9a44782c10105b93962daa8dba304d7f87"},
			want:    []string{"GhWTZqLPHRK8KfuT6yo1wGisQzn4cXrbPP"},
			want2:   true,
			wantErr: false,
		},
		{
			name:    "P2PK compressed",
			args:    args{script: "21020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9ac"},
			want:    []string{"QKKEbCNAV7BYdtfSb3cQcJ7QSmFMvtXETz"},
			want2:   false,
			wantErr: false,
		},
		{
			name:    "P2PK uncompressed",
			args:    args{script: "41041057356b91bfd3efeff5fc0fa8b865faafafb67bd653c5da2cd16ce15c7b86db0e622c8e1e135f68918a23601eb49208c1ac72c7b64a4ee99c396cf788da16ccac"},
			want:    []string{"QDoUiWY7iZXDrkBzXdk6dru8DbvGqExXuf"},
			want2:   false,
			wantErr: false,
		},
	}

	parser := NewLiquidParser(GetChainParams("main"), &btc.Configuration{})

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			b, _ := hex.DecodeString(tt.args.script)
			got, got2, err := parser.GetAddressesFromAddrDesc(b)
			if (err != nil) != tt.wantErr {
				t.Errorf("GetAddressesFromAddrDesc() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got, tt.want)
			}
			if !reflect.DeepEqual(got2, tt.want2) {
				t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got2, tt.want2)
			}
		})
	}
}

var (
	testTx1 bchain.Tx

	testTxPacked1 = "[encoded data, 7412 characters]"
)

func init() {
	testTx1 = bchain.Tx{
		Hex:       "[encoded data, 6762 characters]",
		Blocktime: 1544039759,
		Time:      1544039759,
		Txid:      "7aa1af9481f2d744c96015b1baea6ba753790971ff265adfd93775de0234bfd6",
		LockTime:  0,
		Version:   2,
		Vin: []bchain.Vin{
			{
				ScriptSig: bchain.ScriptSig{
					Hex: "483045022100ae926c96c746308e7488e022f4ad1db94d5d0c8683f6fa6ded3afb13d8e20578022074aa8ebfe20adaf25beed70c60cfb5007278bec17875f11f7a5b3c86eb60a96901210391abdcd113c40b56f13a548e8624d6ad8d7a162b33ef81020d046cadbda26637",
				},
				Txid:     "757d23cec40eef9728417e68a5c6fb70b35e4fe58d34da55f305b013d24795a9",
				Vout:     2,
				Sequence: 4294967294,
			},
		},
		Vout: []bchain.Vout{
			{
				N: 0,
				ScriptPubKey: bchain.ScriptPubKey{
					Hex: "76a914d79c1c8b67a0275c60e33b67bbd0e19a79b9276388ac",
					Addresses: []string{
						"QGvRRFXBM2feXuU39EwHNuYYSrnM3HaUyM",
					},
				},
			},
			{
				ValueSat: *big.NewInt(0),
				N:        1,
				ScriptPubKey: bchain.ScriptPubKey{
					Hex: "6a23426c6f636b73747265616d2e696e666f206973206120636f6f6c206578706c6f726572",
				},
			},
			{
				ValueSat: *big.NewInt(1152),
				N:        2,
				ScriptPubKey: bchain.ScriptPubKey{
					Hex: "",
				},
			},
		},
	}
}

func Test_PackTx(t *testing.T) {
	type args struct {
		tx        bchain.Tx
		height    uint32
		blockTime int64
		parser    *LiquidParser
	}
	tests := []struct {
		name    string
		args    args
		want    string
		wantErr bool
	}{
		{
			name: "liquid-1",
			args: args{
				tx:        testTx1,
				height:    82055,
				blockTime: 1544039759,
				parser:    NewLiquidParser(GetChainParams("main"), &btc.Configuration{}),
			},
			want:    testTxPacked1,
			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 Test_UnpackTx(t *testing.T) {
	type args struct {
		packedTx string
		parser   *LiquidParser
	}
	tests := []struct {
		name    string
		args    args
		want    *bchain.Tx
		want1   uint32
		wantErr bool
	}{
		{
			name: "liquid-1",
			args: args{
				packedTx: testTxPacked1,
				parser:   NewLiquidParser(GetChainParams("main"), &btc.Configuration{}),
			},
			want:    &testTx1,
			want1:   82055,
			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)
			}
		})
	}
}
