package exchain

import (
	"encoding/json"
	"github.com/exchain/go-exchain/op-service/eth"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/holiman/uint256"
	"math/big"
)

type TxType string

const (
	SignProxyTx        TxType = "sign_proxy"         // update a signer proxy public key.
	DepositTx          TxType = "deposit"            // deposit usdt/usdc from l1 to exchain.
	WithdrawTx         TxType = "withdraw"           // withdraw usdt/usdc from exchain to l1.
	CreateOrderBookTx  TxType = "create_order_book"  // create a new orderbook.
	DisableOrderBookTx TxType = "disable_order_book" // disable an existing orderbook.
	LimitTx            TxType = "limit"              // make a limit order.
	MarketTx           TxType = "market"             // make a market order.
	CancelTx           TxType = "cancel"             // cancel an order.
)

type Signature struct {
	R *uint256.Int
	S *uint256.Int
	V byte
}

type Transaction struct {
	User      common.Address  `json:"user"`
	Nonce     uint256.Int     `json:"nonce"`
	Type      TxType          `json:"type"`
	Proxy     bool            `json:"proxy"`
	Data      json.RawMessage `json:"data"`
	Signature Signature       `json:"signature"`
}

type TransactionReceipt struct {
	Hash      common.Hash `json:"hash"`
	TxType    TxType      `json:"txType"`
	Status    uint8       `json:"status"`
	BlockHash common.Hash `json:"blockHash"`
	Content   []eth.Data  `json:"content"` // content is difference by txType.
}

type DepositTxData struct {
	// SourceHash uniquely identifies the source of the deposit
	SourceHash common.Hash
	// From is exposed through the types.Signer, not through TxData
	From common.Address
	// nil means contract creation
	To *common.Address
	// Mint is minted on L2, locked on L1, nil if no minting.
	Mint *big.Int
	// Value is transferred from L2 balance, executed after Mint (if any)
	Value *big.Int
	// Field indicating if this transaction is exempt from the L2 gas limit.
	IsSystemTransaction bool
	// Normal Tx data
	Data []byte
}

type LimitTxData struct {
	Symbol   string      `json:"symbol"`
	Side     uint8       `json:"side"`
	Price    uint256.Int `json:"price"`
	Quantity uint256.Int `json:"quantity"`
}

type MarketTxData struct {
	Symbol   string      `json:"symbol"`
	Side     uint8       `json:"side"`
	Quantity uint256.Int `json:"quantity"`
}

func (tx Transaction) SigHash() common.Hash {
	data := make([]byte, 0)
	data = append(data, tx.User.Bytes()...)
	data = append(data, tx.Nonce.Bytes()...)
	data = append(data, tx.Type...)
	if tx.Proxy {
		data = append(data, byte(1))
	} else {
		data = append(data, byte(0))
	}
	txdata, _ := json.Marshal(tx.Data)
	data = append(data, txdata...)

	return crypto.Keccak256Hash(data)
}

func (tx Transaction) Verify() bool {
	return true
	//if tx.Proxy {
	//	// get user proxy public.
	//	var public ProxyPublickey
	//	pubkey, err := crypto.UnmarshalPubkey(public[:])
	//	if err != nil {
	//		return false
	//	} else {
	//		crypto.VerifySignature()
	//	}
	//
	//}

}
