package evm

import (
	"fmt"
	"math/big"
	"strings"
	"testing"

	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/stretchr/testify/assert"

	ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v2"

	"github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/keeper_registry_wrapper2_0"
)

func TestUnpackTransmitTxInput(t *testing.T) {
	registryABI, err := abi.JSON(strings.NewReader(keeper_registry_wrapper2_0.KeeperRegistryABI))
	assert.NoError(t, err)

	packer := &evmRegistryPackerV2_0{abi: registryABI}
	decodedReport, err := packer.UnpackTransmitTxInput(hexutil.MustDecode("0x00011a04d404e571ead64b2f08cfae623a0d96b9beb326c20e322001cbbd344700000000000000000000000000000000000000000000000000000000000d580e35681c68a0426c30f4686e837c0cd7864200f48dbfe48c80c51f92aa5ac607b300000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002e00000000000000000000000000000000000000000000000000000000000000360000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000773594000000000000000000000000000000000000000000000000000010fb9cd2f34a00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000001de1256139081c6b165a3aee0432f605d3dee0e6087ea53b46ca9478c253ea9c8000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000827075c4bacd41884f60c2ca7af3630400bedd92ad7ad0ba4e1f000e70297de0573e180000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000a8c0000000000000000000000000000000000000000000000000000000000086470000000000000000000000000000000000000000000000000000000000000000326e2b521089d44f1457ae51b3f8d76e8577e08c4af9374bdc62aebbfad081a78a13941ab209ad44a905ee0fd704a46b2ebc022dcb60659bed87342fd94dadb70827af523f59c7c9bb8dcc77e959b0476869612e8cf84e63a2e9a5617290633f70000000000000000000000000000000000000000000000000000000000000003723d77998618c5959396115fc61380215e0395f68c18a6cf0647c3e759ee013040c2967fdd369aac59b464f931dacd7b8863498757eda53a9f6a4b6150f2dbe640771f3c242c297265c36c5e78f4c660ae74dcd1f5bda8687b6afed3d3f27e0d"))
	assert.NoError(t, err)

	// We expect one upkeep ID in the report at block number
	var expectedBlock uint32 = 8548469
	expectedID, _ := new(big.Int).SetString("100445849710294316610676143149039812931260394722330855891004881602834541226440", 10)

	assert.Len(t, decodedReport, 1)

	rpt, ok := decodedReport[0].(EVMAutomationUpkeepResult20)
	assert.True(t, ok)

	assert.Equal(t, expectedBlock, rpt.Block)
	assert.Equal(t, rpt.ID.String(), expectedID.String())
}

func TestUnpackTransmitTxInputErrors(t *testing.T) {
	tests := []struct {
		Name    string
		RawData string
	}{
		{
			Name:    "Empty Data",
			RawData: "0x",
		},
		{
			Name:    "Random Data",
			RawData: "0x2f08cfae623a0d96b9beb326c20e322001cbbd344700",
		},
	}
	for _, test := range tests {
		t.Run(test.Name, func(t *testing.T) {
			abi, err := abi.JSON(strings.NewReader(keeper_registry_wrapper2_0.KeeperRegistryABI))
			assert.NoError(t, err)

			packer := &evmRegistryPackerV2_0{abi: abi}
			_, err = packer.UnpackTransmitTxInput(hexutil.MustDecode(test.RawData))
			assert.Error(t, err)
		})
	}
}

func TestUnpackCheckResults(t *testing.T) {
	registryABI, err := abi.JSON(strings.NewReader(keeper_registry_wrapper2_0.KeeperRegistryABI))
	if err != nil {
		assert.NoError(t, err)
	}

	upkeepId, _ := new(big.Int).SetString("1843548457736589226156809205796175506139185429616502850435279853710366065936", 10)

	tests := []struct {
		Name           string
		UpkeepKey      ocr2keepers.UpkeepKey
		RawData        string
		ExpectedResult EVMAutomationUpkeepResult20
	}{
		{
			Name:      "upkeep not needed",
			UpkeepKey: ocr2keepers.UpkeepKey(fmt.Sprintf("19447615|%s", upkeepId)),
			RawData:   "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000421c000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000c8caf37f3b3890000000000000000000000000000000000000000000000000000000000000000",
			ExpectedResult: EVMAutomationUpkeepResult20{
				Block:            19447615,
				ID:               upkeepId,
				Eligible:         false,
				FailureReason:    UPKEEP_FAILURE_REASON_UPKEEP_NOT_NEEDED,
				GasUsed:          big.NewInt(16924),
				PerformData:      nil,
				FastGasWei:       big.NewInt(1000000000),
				LinkNative:       big.NewInt(3532383906411401),
				CheckBlockNumber: 0,
				CheckBlockHash:   [32]byte{},
				ExecuteGas:       5000000,
			},
		},
		{
			Name:      "target check reverted",
			UpkeepKey: ocr2keepers.UpkeepKey(fmt.Sprintf("19448272|%s", upkeepId)),
			RawData:   "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000007531000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000c8caf37f3b3890000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000008914039bf676e20aad43a5642485e666575ed0d927a4b5679745e947e7d125ee2687c10000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000024462e8a50d00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000128c1d000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000009666565644944537472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000184554482d5553442d415242495452554d2d544553544e4554000000000000000000000000000000000000000000000000000000000000000000000000000000184254432d5553442d415242495452554d2d544553544e45540000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d6265720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000000000000000000000",
			ExpectedResult: EVMAutomationUpkeepResult20{
				Block:            19448272,
				ID:               upkeepId,
				Eligible:         false,
				FailureReason:    UPKEEP_FAILURE_REASON_TARGET_CHECK_REVERTED,
				GasUsed:          big.NewInt(30001),
				PerformData:      []byte{98, 232, 165, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 40, 193, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 102, 101, 101, 100, 73, 68, 83, 116, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 69, 84, 72, 45, 85, 83, 68, 45, 65, 82, 66, 73, 84, 82, 85, 77, 45, 84, 69, 83, 84, 78, 69, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 66, 84, 67, 45, 85, 83, 68, 45, 65, 82, 66, 73, 84, 82, 85, 77, 45, 84, 69, 83, 84, 78, 69, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 98, 108, 111, 99, 107, 78, 117, 109, 98, 101, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
				FastGasWei:       big.NewInt(1000000000),
				LinkNative:       big.NewInt(3532383906411401),
				CheckBlockNumber: 8983555,
				CheckBlockHash:   [32]byte{155, 246, 118, 226, 10, 173, 67, 165, 100, 36, 133, 230, 102, 87, 94, 208, 217, 39, 164, 181, 103, 151, 69, 233, 71, 231, 209, 37, 238, 38, 135, 193},
				ExecuteGas:       5000000,
			},
		},
	}
	for _, test := range tests {
		t.Run(test.Name, func(t *testing.T) {
			packer := &evmRegistryPackerV2_0{abi: registryABI}
			rs, err := packer.UnpackCheckResult(test.UpkeepKey, test.RawData)
			assert.NoError(t, err)
			assert.Equal(t, test.ExpectedResult, rs)
		})
	}
}

func TestUnpackPerformResult(t *testing.T) {
	registryABI, err := abi.JSON(strings.NewReader(keeper_registry_wrapper2_0.KeeperRegistryABI))
	if err != nil {
		assert.NoError(t, err)
	}

	tests := []struct {
		Name    string
		RawData string
	}{
		{
			Name:    "unpack success",
			RawData: "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000a52d",
		},
	}
	for _, test := range tests {
		t.Run(test.Name, func(t *testing.T) {
			packer := &evmRegistryPackerV2_0{abi: registryABI}
			rs, err := packer.UnpackPerformResult(test.RawData)
			assert.NoError(t, err)
			assert.True(t, rs)
		})
	}
}
