package compressor

import (
	"fmt"

	"github.com/0xsequence/ethkit/go-ethereum/common"
)

type EncodeType int

const (
	Stateless EncodeType = iota
	Mirror
	ReadStorage
	WriteStorage
)

const (
	METHOD_EXECUTE_SEQUENCE_TX uint = iota
	METHOD_EXECUTE_SEQUENCE_N_TXS
	METHOD_READ_ADDRESS
	METHOD_READ_BYTES32
	METHOD_READ_SIZES
	METHOD_READ_STORAGE_SLOTS
	METHOD_DECODE_SEQUENCE_TX
	METHOD_DECODE_SEQUENCE_N_TXS
	METHOD_EXECUTE_CALL
	METHOD_EXECUTE_CALL_RETURN
	METHOD_EXECUTE_N_CALLS
	METHOD_DECODE_CALL
	METHOD_DECODE_N_CALLS
	METHOD_DECODE_ANY
)

const (
	FLAG_NO_OP uint = iota
	FLAG_READ_WORD_1
	FLAG_READ_WORD_2
	FLAG_READ_WORD_3
	FLAG_READ_WORD_4
	FLAG_READ_WORD_5
	FLAG_READ_WORD_6
	FLAG_READ_WORD_7
	FLAG_READ_WORD_8
	FLAG_READ_WORD_9
	FLAG_READ_WORD_10
	FLAG_READ_WORD_11
	FLAG_READ_WORD_12
	FLAG_READ_WORD_13
	FLAG_READ_WORD_14
	FLAG_READ_WORD_15
	FLAG_READ_WORD_16
	FLAG_READ_WORD_17
	FLAG_READ_WORD_18
	FLAG_READ_WORD_19
	FLAG_READ_WORD_20
	FLAG_READ_WORD_21
	FLAG_READ_WORD_22
	FLAG_READ_WORD_23
	FLAG_READ_WORD_24
	FLAG_READ_WORD_25
	FLAG_READ_WORD_26
	FLAG_READ_WORD_27
	FLAG_READ_WORD_28
	FLAG_READ_WORD_29
	FLAG_READ_WORD_30
	FLAG_READ_WORD_31
	FLAG_READ_WORD_32
	FLAG_READ_WORD_INV
	FLAG_READ_N_BYTES
	FLAG_WRITE_ZEROS
	FLAG_NESTED_N_FLAGS_S
	FLAG_NESTED_N_FLAGS_L
	FLAG_SAVE_ADDRESS
	FLAG_READ_ADDRESS_2
	FLAG_READ_ADDRESS_3
	FLAG_READ_ADDRESS_4
	FLAG_SAVE_BYTES32
	FLAG_READ_BYTES32_2
	FLAG_READ_BYTES32_3
	FLAG_READ_BYTES32_4
	FLAG_READ_STORE_FLAG_S
	FLAG_READ_STORE_FLAG_L
	FLAG_POW_2
	FLAG_POW_2_MINUS_1
	FLAG_POW_10
	FLAG_POW_10_MANTISSA_S
	FLAG_POW_10_MANTISSA_L
	FLAG_ABI_0_PARAM
	FLAG_ABI_1_PARAM
	FLAG_ABI_2_PARAMS
	FLAG_ABI_3_PARAMS
	FLAG_ABI_4_PARAMS
	FLAG_ABI_5_PARAMS
	FLAG_ABI_6_PARAMS
	FLAG_READ_DYNAMIC_ABI
	FLAG_MIRROR_FLAG_S
	FLAG_MIRROR_FLAG_L
	FLAG_COPY_CALLDATA_S
	FLAG_COPY_CALLDATA_L
	FLAG_COPY_CALLDATA_XL
	FLAG_SEQUENCE_EXECUTE
	FLAG_SEQUENCE_SELF_EXECUTE
	FLAG_SEQUENCE_SIGNATURE_W0
	FLAG_SEQUENCE_SIGNATURE_W1
	FLAG_SEQUENCE_SIGNATURE_W2
	FLAG_SEQUENCE_SIGNATURE_W3
	FLAG_SEQUENCE_SIGNATURE_W4
	FLAG_SEQUENCE_ADDRESS_W0
	FLAG_SEQUENCE_ADDRESS_W1
	FLAG_SEQUENCE_ADDRESS_W2
	FLAG_SEQUENCE_ADDRESS_W3
	FLAG_SEQUENCE_ADDRESS_W4
	FLAG_SEQUENCE_NODE
	FLAG_SEQUENCE_BRANCH
	FLAG_SEQUENCE_SUBDIGEST
	FLAG_SEQUENCE_NESTED
	FLAG_SEQUENCE_DYNAMIC_SIGNATURE
	FLAG_SEQUENCE_SIG_NO_CHAIN
	FLAG_SEQUENCE_SIG
	FLAG_SEQUENCE_L_SIG_NO_CHAIN
	FLAG_SEQUENCE_L_SIG
	FLAG_SEQUENCE_READ_CHAINED_S
	FLAG_SEQUENCE_READ_CHAINED_L
)

func FlagNames() map[string]uint {
	names := make(map[string]uint)

	for i := uint(0); i <= LITERAL_ZERO; i++ {
		switch i {
		case FLAG_POW_10_MANTISSA_S:
			names["FLAG_POW_10_MANTISSA_S"] = i
		case FLAG_READ_WORD_1:
			names["FLAG_READ_WORD_1"] = i
		case FLAG_READ_WORD_2:
			names["FLAG_READ_WORD_2"] = i
		case FLAG_READ_WORD_3:
			names["FLAG_READ_WORD_3"] = i
		case FLAG_READ_WORD_4:
			names["FLAG_READ_WORD_4"] = i
		case FLAG_READ_WORD_5:
			names["FLAG_READ_WORD_5"] = i
		case FLAG_READ_WORD_6:
			names["FLAG_READ_WORD_6"] = i
		case FLAG_READ_WORD_7:
			names["FLAG_READ_WORD_7"] = i
		case FLAG_READ_WORD_8:
			names["FLAG_READ_WORD_8"] = i
		case FLAG_READ_WORD_9:
			names["FLAG_READ_WORD_9"] = i
		case FLAG_READ_WORD_10:
			names["FLAG_READ_WORD_10"] = i
		case FLAG_READ_WORD_11:
			names["FLAG_READ_WORD_11"] = i
		case FLAG_READ_WORD_12:
			names["FLAG_READ_WORD_12"] = i
		case FLAG_READ_WORD_13:
			names["FLAG_READ_WORD_13"] = i
		case FLAG_READ_WORD_14:
			names["FLAG_READ_WORD_14"] = i
		case FLAG_READ_WORD_15:
			names["FLAG_READ_WORD_15"] = i
		case FLAG_READ_WORD_16:
			names["FLAG_READ_WORD_16"] = i
		case FLAG_READ_WORD_17:
			names["FLAG_READ_WORD_17"] = i
		case FLAG_READ_WORD_18:
			names["FLAG_READ_WORD_18"] = i
		case FLAG_READ_WORD_19:
			names["FLAG_READ_WORD_19"] = i
		case FLAG_READ_WORD_20:
			names["FLAG_READ_WORD_20"] = i
		case FLAG_READ_WORD_21:
			names["FLAG_READ_WORD_21"] = i
		case FLAG_READ_WORD_22:
			names["FLAG_READ_WORD_22"] = i
		case FLAG_READ_WORD_23:
			names["FLAG_READ_WORD_23"] = i
		case FLAG_READ_WORD_24:
			names["FLAG_READ_WORD_24"] = i
		case FLAG_READ_WORD_25:
			names["FLAG_READ_WORD_25"] = i
		case FLAG_READ_WORD_26:
			names["FLAG_READ_WORD_26"] = i
		case FLAG_READ_WORD_27:
			names["FLAG_READ_WORD_27"] = i
		case FLAG_READ_WORD_28:
			names["FLAG_READ_WORD_28"] = i
		case FLAG_READ_WORD_29:
			names["FLAG_READ_WORD_29"] = i
		case FLAG_READ_WORD_30:
			names["FLAG_READ_WORD_30"] = i
		case FLAG_READ_WORD_31:
			names["FLAG_READ_WORD_31"] = i
		case FLAG_READ_WORD_32:
			names["FLAG_READ_WORD_32"] = i
		case FLAG_SAVE_ADDRESS:
			names["FLAG_SAVE_ADDRESS"] = i
		case FLAG_SAVE_BYTES32:
			names["FLAG_SAVE_BYTES32"] = i
		case FLAG_READ_ADDRESS_2:
			names["FLAG_READ_ADDRESS_2"] = i
		case FLAG_READ_ADDRESS_3:
			names["FLAG_READ_ADDRESS_3"] = i
		case FLAG_READ_ADDRESS_4:
			names["FLAG_READ_ADDRESS_4"] = i
		case FLAG_SEQUENCE_EXECUTE:
			names["FLAG_SEQUENCE_EXECUTE"] = i
		case FLAG_READ_BYTES32_2:
			names["FLAG_READ_BYTES32_2"] = i
		case FLAG_READ_BYTES32_3:
			names["FLAG_READ_BYTES32_3"] = i
		case FLAG_READ_BYTES32_4:
			names["FLAG_READ_BYTES32_4"] = i
		case FLAG_POW_10_MANTISSA_L:
			names["FLAG_POW_10_MANTISSA_L"] = i
		case FLAG_READ_N_BYTES:
			names["FLAG_READ_N_BYTES"] = i
		case FLAG_POW_2:
			names["FLAG_POW_2"] = i
		case FLAG_ABI_0_PARAM:
			names["FLAG_ABI_0_PARAM"] = i
		case FLAG_ABI_1_PARAM:
			names["FLAG_ABI_1_PARAM"] = i
		case FLAG_ABI_2_PARAMS:
			names["FLAG_ABI_2_PARAMS"] = i
		case FLAG_ABI_3_PARAMS:
			names["FLAG_ABI_3_PARAMS"] = i
		case FLAG_ABI_4_PARAMS:
			names["FLAG_ABI_4_PARAMS"] = i
		case FLAG_ABI_5_PARAMS:
			names["FLAG_ABI_5_PARAMS"] = i
		case FLAG_ABI_6_PARAMS:
			names["FLAG_ABI_6_PARAMS"] = i
		case FLAG_NESTED_N_FLAGS_S:
			names["FLAG_NESTED_N_FLAGS_S"] = i
		case FLAG_NESTED_N_FLAGS_L:
			names["FLAG_NESTED_N_FLAGS_L"] = i
		case FLAG_SEQUENCE_SIGNATURE_W0:
			names["FLAG_SEQUENCE_SIGNATURE_W0"] = i
		case FLAG_SEQUENCE_SIGNATURE_W1:
			names["FLAG_SEQUENCE_SIGNATURE_W1"] = i
		case FLAG_SEQUENCE_SIGNATURE_W2:
			names["FLAG_SEQUENCE_SIGNATURE_W2"] = i
		case FLAG_SEQUENCE_SIGNATURE_W3:
			names["FLAG_SEQUENCE_SIGNATURE_W3"] = i
		case FLAG_SEQUENCE_SIGNATURE_W4:
			names["FLAG_SEQUENCE_SIGNATURE_W4"] = i
		case FLAG_SEQUENCE_ADDRESS_W0:
			names["FLAG_SEQUENCE_ADDRESS_W0"] = i
		case FLAG_SEQUENCE_ADDRESS_W1:
			names["FLAG_SEQUENCE_ADDRESS_W1"] = i
		case FLAG_SEQUENCE_ADDRESS_W2:
			names["FLAG_SEQUENCE_ADDRESS_W2"] = i
		case FLAG_SEQUENCE_ADDRESS_W3:
			names["FLAG_SEQUENCE_ADDRESS_W3"] = i
		case FLAG_SEQUENCE_ADDRESS_W4:
			names["FLAG_SEQUENCE_ADDRESS_W4"] = i
		case FLAG_SEQUENCE_NODE:
			names["FLAG_SEQUENCE_NODE"] = i
		case FLAG_SEQUENCE_BRANCH:
			names["FLAG_SEQUENCE_BRANCH"] = i
		case FLAG_SEQUENCE_SUBDIGEST:
			names["FLAG_SEQUENCE_SUBDIGEST"] = i
		case FLAG_SEQUENCE_NESTED:
			names["FLAG_SEQUENCE_NESTED"] = i
		case FLAG_SEQUENCE_DYNAMIC_SIGNATURE:
			names["FLAG_SEQUENCE_DYNAMIC_SIGNATURE"] = i
		case FLAG_SEQUENCE_SIG_NO_CHAIN:
			names["FLAG_SEQUENCE_SIG_NO_CHAIN"] = i
		case FLAG_SEQUENCE_SIG:
			names["FLAG_SEQUENCE_SIG"] = i
		case FLAG_SEQUENCE_L_SIG_NO_CHAIN:
			names["FLAG_SEQUENCE_L_SIG_NO_CHAIN"] = i
		case FLAG_SEQUENCE_L_SIG:
			names["FLAG_SEQUENCE_L_SIG"] = i
		case FLAG_SEQUENCE_READ_CHAINED_S:
			names["FLAG_SEQUENCE_READ_CHAINED_S"] = i
		case FLAG_SEQUENCE_READ_CHAINED_L:
			names["FLAG_SEQUENCE_READ_CHAINED_L"] = i
		case FLAG_READ_DYNAMIC_ABI:
			names["FLAG_READ_DYNAMIC_ABI"] = i
		case FLAG_NO_OP:
			names["FLAG_NO_OP"] = i
		case FLAG_MIRROR_FLAG_S:
			names["FLAG_MIRROR_FLAG_S"] = i
		case FLAG_COPY_CALLDATA_S:
			names["FLAG_COPY_CALLDATA_S"] = i
		case FLAG_READ_STORE_FLAG_S:
			names["FLAG_READ_STORE_FLAG_S"] = i
		case LITERAL_ZERO:
			names["LITERAL_ZERO"] = i
		case FLAG_WRITE_ZEROS:
			names["FLAG_WRITE_ZEROS"] = i
		case FLAG_POW_10:
			names["FLAG_POW_10"] = i
		case FLAG_SEQUENCE_SELF_EXECUTE:
			names["FLAG_SEQUENCE_SELF_EXECUTE"] = i
		case FLAG_POW_2_MINUS_1:
			names["FLAG_POW_2_MINUS_1"] = i
		case FLAG_MIRROR_FLAG_L:
			names["FLAG_MIRROR_FLAG_L"] = i
		case FLAG_COPY_CALLDATA_L:
			names["FLAG_COPY_CALLDATA_L"] = i
		case FLAG_COPY_CALLDATA_XL:
			names["FLAG_COPY_CALLDATA_XL"] = i
		case FLAG_READ_WORD_INV:
			names["FLAG_READ_WORD_INV"] = i
		case FLAG_READ_STORE_FLAG_L:
			names["FLAG_READ_STORE_FLAG_L"] = i
		default:
			panic(fmt.Sprintf("unknown flag: %d", i))
		}
	}

	return names
}

const LITERAL_ZERO = FLAG_SEQUENCE_READ_CHAINED_L + 1
const MAX_LITERAL = 0xff - LITERAL_ZERO

const BYTES4_TABLE = "00000000a9059cbb095ea7b37ff36ab538ed173918cbafe5202ee0edfb3bdb41e2bbb158ab834bab6ea056a923b872dda68a76cc5f5755298803dbeea22cb465c89e43612da0340990411a321cff79cd223da1ba2e1a7d4df305d71939125215d0e30db0f7654176a694fc3a1a695230b6b55f25791ac94764887334c658695c441a3e704f1d48324a25d94aa454dfa9c18a84bce2b39746178979aec9807539ddd81f82a8a41c70cf557fe33d18b9129cec63924ab0d1900dcd7a6cd9627aa49149bafe672a9400dfbe4a31c6bf3262f242432ae5ab4da240c10f192e7ba6efc23e1a211aa3a008d6b347f7ded9382a00000003e9fad8eefaebafa8ae169a50e8e3370041fe00a0fa558b712e95b6c8c48fdfca000000006a80c33f627dd56a5c11d7954946e2065e83b463ca722cdcfb90b32000000008f7c1e582a32fe0a1db006a75000000010002191ce6d66ac8a0712d685d5d442296aa7368d3392ddf0ea5812fa5d754d1d29dff129979ef457901451ca64f797659d667a500032587865a6b4f379607f57c02520082d2697fc11695488758a5f34e71d92d9ddd67ba183d4e0b8f69c188e3dec8fbedc9af952d2da8066a761202a9b1d507ca120b1ff14fcbc8961c9ae442842e0e2195995c94b918de608060405174e8532505c3d98568523a0e89439bd149d05cefef39a14ce6931a000225879bfcb236415565b0454a2ab3ce558087f7a1696342966c688b4cb0ec4faa8a26e4a76726e8eda9df1519cdeb356282bfe17376b5009952eb3d7989fe34b0793b38bcdfc0f053566e02751cecc01a8c84f463e18e3cd18ca029ada03907d6b3483805550fa59f3e0c89bbb8b2c5ebeaec4997adb6f5e54063761610fcb88a802f3ccfd60b2e2d726ca4202615b44848f51610ca95bcf64e0579b177ec22895118ed436a474d474898c0f4ed31b967cb0ca6e158f8db7fd4089120491ca415bcad8201aa3f6e5110ae5312ea8e3df02124b77d239ba67a6a45156e29f6241735bbd017e8c73f7658fd86b2ecc4c44193c39bc12042d96a094a13d98d135d4c66a3ad4451a32e17de789ec9b36be47d166cbfff3b87f884e54a0b020003ad58bdd147e7ef24bad42590c8fd6ed002032587c6427474f6162b01baa2abde1ff013f11846eac55915d806f6aa658b00024a9c564a515869328dec4454b20df5298aca853828b6f06427e5b6b4af05f3fef3a352a438b81249c58bfeab2e5af9d83bb568c2c5fb02022587d586d8e0db254e5005eec2890e7527028f4af52f6a627842508c1dbd0f694584a6417ed63049105d1e9a6950d9caed120103258748d5c7e3be389d577430e0c649b780f00af49149d508e6238e1e280cae47bea8683fa88d5db3b4df1e83409a852a12e3c2998238343009a2daa6d5560f0439589c1298a06aa1e6d24d559317"

func LoadBytes4() map[string]uint {
	btable := common.Hex2Bytes(BYTES4_TABLE)
	table := make(map[string]uint)

	for i := uint(0); i < uint(len(btable)); i += 4 {
		table[string(btable[i:i+4])] = i / 4
	}

	return table
}
