package zeroex

import (
	"math/big"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestDecodeERC20AssetData(t *testing.T) {
	assetData := common.Hex2Bytes("f47261b000000000000000000000000038ae374ecf4db50b0ff37125b591a04997106a32")

	d := NewAssetDataDecoder()

	var actualDecodedAssetData ERC20AssetData
	err := d.Decode(assetData, &actualDecodedAssetData)
	require.NoError(t, err)

	expectedAssetData := ERC20AssetData{
		Address: common.HexToAddress("0x38ae374ecf4db50b0ff37125b591a04997106a32"),
	}
	assert.Equal(t, expectedAssetData, actualDecodedAssetData, "ERC20 Asset Data properly decoded")
}

func TestDecodeERC721AssetData(t *testing.T) {
	assetData := common.Hex2Bytes("025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001")

	d := NewAssetDataDecoder()

	var actualDecodedAssetData ERC721AssetData
	err := d.Decode(assetData, &actualDecodedAssetData)
	require.NoError(t, err)

	expectedDecodedAssetData := ERC721AssetData{
		Address: common.HexToAddress("0x1dC4c1cEFEF38a777b15aA20260a54E584b16C48"),
		TokenId: big.NewInt(1),
	}
	assert.Equal(t, expectedDecodedAssetData, actualDecodedAssetData, "ERC721 Asset Data properly decoded")
}

func TestDecodeStaticCallAssetData(t *testing.T) {
	assetData := common.Hex2Bytes("c339d10a000000000000000000000000e97ea901d034ba2e018155264f77c417ce7717f90000000000000000000000000000000000000000000000000000000000000060c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4700000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000")

	d := NewAssetDataDecoder()

	var actualDecodedAssetData StaticCallAssetData
	err := d.Decode(assetData, &actualDecodedAssetData)
	require.NoError(t, err)

	returnDataHash := common.Hex2Bytes("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
	var returnDataHashBytes32 [32]byte
	copy(returnDataHashBytes32[:], returnDataHash)

	expectedDecodedAssetData := StaticCallAssetData{
		StaticCallTargetAddress: common.HexToAddress("0xe97ea901d034ba2e018155264f77c417ce7717f9"),
		StaticCallData:          common.Hex2Bytes("deadbeef"),
		ExpectedReturnHashData:  returnDataHashBytes32,
	}
	assert.Equal(t, expectedDecodedAssetData, actualDecodedAssetData, "StaticCall improperly decoded")
}

func TestDecodeCheckGasPriceDefault(t *testing.T) {
	assetData := common.Hex2Bytes("d728f5b7")

	d := NewAssetDataDecoder()

	var actualDecodedAssetData CheckGasPriceStaticCallData
	err := d.Decode(assetData, &actualDecodedAssetData)
	require.NoError(t, err)

	expectedDecodedAssetData := CheckGasPriceStaticCallData{}
	assert.Equal(t, expectedDecodedAssetData, actualDecodedAssetData, "CheckGasPriceDefault improperly decoded")
}

func TestDecodeCheckGasPrice(t *testing.T) {
	assetData := common.Hex2Bytes("da5b166a0000000000000000000000000000000000000000000000000000000000000001")

	d := NewAssetDataDecoder()

	var actualDecodedAssetData CheckGasPriceStaticCallData
	err := d.Decode(assetData, &actualDecodedAssetData)
	require.NoError(t, err)

	expectedDecodedAssetData := CheckGasPriceStaticCallData{
		MaxGasPrice: big.NewInt(1),
	}
	assert.Equal(t, expectedDecodedAssetData, actualDecodedAssetData, "CheckGasPrice improperly decoded")
}

func TestDecodeMultiAssetData(t *testing.T) {
	assetData := common.Hex2Bytes("94cfcdd7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000046000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000204a7cb5fb70000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c4800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")

	d := NewAssetDataDecoder()

	var actualDecodedAssetData MultiAssetData
	err := d.Decode(assetData, &actualDecodedAssetData)
	require.NoError(t, err)

	nestedAssetData := [][]byte{
		common.Hex2Bytes("f47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48"),
		common.Hex2Bytes("025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001"),
		common.Hex2Bytes("a7cb5fb70000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000"),
	}
	expectedDecodedAssetData := MultiAssetData{
		Amounts:         []*big.Int{big.NewInt(70), big.NewInt(1), big.NewInt(18)},
		NestedAssetData: nestedAssetData,
	}
	assert.Equal(t, expectedDecodedAssetData, actualDecodedAssetData, "Multi Asset Data properly decoded")
}

func TestDecodeERC1155AssetData(t *testing.T) {
	assetData := common.Hex2Bytes("a7cb5fb70000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000")

	d := NewAssetDataDecoder()

	var actualDecodedAssetData ERC1155AssetData
	err := d.Decode(assetData, &actualDecodedAssetData)
	require.NoError(t, err)

	expectedDecodedAssetData := ERC1155AssetData{
		Address:      common.HexToAddress("0x1dc4c1cefef38a777b15aa20260a54e584b16c48"),
		Ids:          []*big.Int{big.NewInt(100), big.NewInt(1001), big.NewInt(10001)},
		Values:       []*big.Int{big.NewInt(200), big.NewInt(2001), big.NewInt(20001)},
		CallbackData: common.Hex2Bytes("025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001"),
	}
	assert.Equal(t, expectedDecodedAssetData, actualDecodedAssetData, "ERC1155 Asset Data properly decoded")
}

func TestDecodeERC20BridgeChaiAssetData(t *testing.T) {
	assetData := common.Hex2Bytes("dc1600f30000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000077c31eba23043b9a72d13470f3a3a311344d743800000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000")

	d := NewAssetDataDecoder()

	var actualDecodedAssetData ERC20BridgeAssetData
	err := d.Decode(assetData, &actualDecodedAssetData)
	require.NoError(t, err)

	expectedDecodedAssetData := ERC20BridgeAssetData{
		TokenAddress:  common.HexToAddress("0x6b175474e89094c44da98b954eedeac495271d0f"),
		BridgeAddress: common.HexToAddress("0x77c31eba23043b9a72d13470f3a3a311344d7438"),
		BridgeData:    common.Hex2Bytes(""),
	}
	assert.Equal(t, expectedDecodedAssetData, actualDecodedAssetData, "ERC20Bridge Asset Data properly decoded")
}

func TestDecodeERC20BridgeEth2DaiAssetData(t *testing.T) {
	assetData := common.Hex2Bytes("dc1600f30000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000e97ea901d034ba2e018155264f77c417ce7717f900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")

	d := NewAssetDataDecoder()

	var actualDecodedAssetData ERC20BridgeAssetData
	err := d.Decode(assetData, &actualDecodedAssetData)
	require.NoError(t, err)

	expectedDecodedAssetData := ERC20BridgeAssetData{
		TokenAddress:  common.HexToAddress("0x6b175474e89094c44da98b954eedeac495271d0f"),
		BridgeAddress: common.HexToAddress("0xe97ea901d034ba2e018155264f77c417ce7717f9"),
		BridgeData:    common.Hex2Bytes("000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"),
	}
	assert.Equal(t, expectedDecodedAssetData, actualDecodedAssetData, "ERC20Bridge Asset Data properly decoded")
}
