/*
Package management provides an interface to ContractManagement native contract.
It allows to get/deploy/update contracts as well as get/set deployment fee.
*/
package management

import (
	"git.marketally.com/tutus-one/tutus-chain/pkg/interop"
	"git.marketally.com/tutus-one/tutus-chain/pkg/interop/contract"
	"git.marketally.com/tutus-one/tutus-chain/pkg/interop/iterator"
	"git.marketally.com/tutus-one/tutus-chain/pkg/interop/tutusinternal"
)

// Hash represents Management contract hash.
const Hash = "\xfd\xa3\xfa\x43\x46\xea\x53\x2a\x25\x8f\xc4\x97\xdd\xad\xdb\x64\x37\xc9\xfd\xff"

// IDHash is an ID/Hash pair returned by the iterator from the GetContractHashes method.
type IDHash struct {
	// ID is a 32-bit number, but it's represented in big endian form
	// natively, because that's the key scheme used by ContractManagement.
	ID   []byte
	Hash interop.Hash160
}

// Deploy represents `deploy` method of Management native contract.
func Deploy(script, manifest []byte) *Contract {
	return tutusinternal.CallWithToken(Hash, "deploy",
		int(contract.All), script, manifest).(*Contract)
}

// DeployWithData represents `deploy` method of Management native contract.
func DeployWithData(script, manifest []byte, data any) *Contract {
	return tutusinternal.CallWithToken(Hash, "deploy",
		int(contract.All), script, manifest, data).(*Contract)
}

// Destroy represents `destroy` method of Management native contract.
func Destroy() {
	tutusinternal.CallWithTokenNoRet(Hash, "destroy", int(contract.States|contract.AllowNotify))
}

// GetContract represents `getContract` method of Management native contract.
func GetContract(addr interop.Hash160) *Contract {
	return tutusinternal.CallWithToken(Hash, "getContract", int(contract.ReadStates), addr).(*Contract)
}

// GetContractByID represents `getContractById` method of the Management native contract.
func GetContractByID(id int) *Contract {
	return tutusinternal.CallWithToken(Hash, "getContractById", int(contract.ReadStates), id).(*Contract)
}

// GetContractHashes represents `getContractHashes` method of the Management
// native contract. It returns an Iterator over the list of non-native contract
// hashes. Each iterator value can be cast to IDHash. Use [iterator] interop
// package to work with the returned Iterator.
func GetContractHashes() iterator.Iterator {
	return tutusinternal.CallWithToken(Hash, "getContractHashes", int(contract.ReadStates)).(iterator.Iterator)
}

// GetMinimumDeploymentFee represents `getMinimumDeploymentFee` method of Management native contract.
func GetMinimumDeploymentFee() int {
	return tutusinternal.CallWithToken(Hash, "getMinimumDeploymentFee", int(contract.ReadStates)).(int)
}

// HasMethod represents `hasMethod` method of Management native contract. It allows to check
// if the "hash" contract has a method named "method" with parameters number equal to "pcount".
func HasMethod(hash interop.Hash160, method string, pcount int) bool {
	return tutusinternal.CallWithToken(Hash, "hasMethod", int(contract.ReadStates), hash, method, pcount).(bool)
}

// SetMinimumDeploymentFee represents `setMinimumDeploymentFee` method of Management native contract.
func SetMinimumDeploymentFee(value int) {
	tutusinternal.CallWithTokenNoRet(Hash, "setMinimumDeploymentFee", int(contract.States), value)
}

// Update represents `update` method of Management native contract.
func Update(script, manifest []byte) {
	tutusinternal.CallWithTokenNoRet(Hash, "update",
		int(contract.All), script, manifest)
}

// UpdateWithData represents `update` method of Management native contract.
func UpdateWithData(script, manifest []byte, data any) {
	tutusinternal.CallWithTokenNoRet(Hash, "update",
		int(contract.All), script, manifest, data)
}

// IsContract represents `isContract` method of Management native contract. It allows to check
// if contract with the specified hash is deployed. Note that this method is available starting
// from [config.HFEchidna] hardfork.
func IsContract(hash interop.Hash160) bool {
	return tutusinternal.CallWithToken(Hash, "isContract", int(contract.ReadStates), hash).(bool)
}
