// Code generated by https://github.com/daog1/solana-anchor-go. DO NOT EDIT.

package pump

import (
	"bytes"
	"fmt"
	ag_spew "github.com/davecgh/go-spew/spew"
	ag_binary "github.com/gagliardetto/binary"
	ag_solanago "github.com/gagliardetto/solana-go"
	ag_text "github.com/gagliardetto/solana-go/text"
	ag_treeout "github.com/gagliardetto/treeout"
)

var ProgramID ag_solanago.PublicKey

func SetProgramID(PublicKey ag_solanago.PublicKey) {
	ProgramID = PublicKey
	ag_solanago.RegisterInstructionDecoder(ProgramID, registryDecodeInstruction)
}

const ProgramName = "Pump"

func init() {
	if !ProgramID.IsZero() {
		ag_solanago.RegisterInstructionDecoder(ProgramID, registryDecodeInstruction)
	}
}

var (
	// Buys tokens from a bonding curve.
	Instruction_Buy = ag_binary.TypeID([8]byte{102, 6, 61, 18, 1, 218, 235, 234})

	// Collects creator_fee from creator_vault to the coin creator account
	Instruction_CollectCreatorFee = ag_binary.TypeID([8]byte{20, 22, 86, 123, 198, 28, 219, 132})

	// Creates a new coin and bonding curve.
	Instruction_Create = ag_binary.TypeID([8]byte{24, 30, 200, 40, 5, 28, 7, 119})

	// Extends the size of program-owned accounts
	Instruction_ExtendAccount = ag_binary.TypeID([8]byte{234, 102, 194, 203, 150, 72, 62, 229})

	// Creates the global state.
	Instruction_Initialize = ag_binary.TypeID([8]byte{175, 175, 109, 31, 13, 152, 155, 237})

	// Migrates liquidity to pump_amm if the bonding curve is complete
	Instruction_Migrate = ag_binary.TypeID([8]byte{155, 234, 231, 146, 236, 158, 162, 30})

	// Sells tokens into a bonding curve.
	Instruction_Sell = ag_binary.TypeID([8]byte{51, 230, 133, 164, 1, 127, 131, 173})

	// Allows Global::set_creator_authority to set the bonding curve creator from Metaplex metadata or input argument
	Instruction_SetCreator = ag_binary.TypeID([8]byte{254, 148, 255, 112, 207, 142, 170, 165})

	// Syncs the bonding curve creator with the Metaplex metadata creator if it exists
	Instruction_SetMetaplexCreator = ag_binary.TypeID([8]byte{138, 96, 174, 217, 48, 85, 197, 246})

	// Sets the global state parameters.
	Instruction_SetParams = ag_binary.TypeID([8]byte{27, 234, 178, 52, 147, 2, 187, 141})

	Instruction_UpdateGlobalAuthority = ag_binary.TypeID([8]byte{227, 181, 74, 196, 208, 21, 97, 213})
)

// InstructionIDToName returns the name of the instruction given its ID.
func InstructionIDToName(id ag_binary.TypeID) string {
	switch id {
	case Instruction_Buy:
		return "Buy"
	case Instruction_CollectCreatorFee:
		return "CollectCreatorFee"
	case Instruction_Create:
		return "Create"
	case Instruction_ExtendAccount:
		return "ExtendAccount"
	case Instruction_Initialize:
		return "Initialize"
	case Instruction_Migrate:
		return "Migrate"
	case Instruction_Sell:
		return "Sell"
	case Instruction_SetCreator:
		return "SetCreator"
	case Instruction_SetMetaplexCreator:
		return "SetMetaplexCreator"
	case Instruction_SetParams:
		return "SetParams"
	case Instruction_UpdateGlobalAuthority:
		return "UpdateGlobalAuthority"
	default:
		return ""
	}
}

type Instruction struct {
	ag_binary.BaseVariant
}

func (inst *Instruction) EncodeToTree(parent ag_treeout.Branches) {
	if enToTree, ok := inst.Impl.(ag_text.EncodableToTree); ok {
		enToTree.EncodeToTree(parent)
	} else {
		parent.Child(ag_spew.Sdump(inst))
	}
}

var InstructionImplDef = ag_binary.NewVariantDefinition(
	ag_binary.AnchorTypeIDEncoding,
	[]ag_binary.VariantType{
		{
			Name: "buy", Type: (*Buy)(nil),
		},
		{
			Name: "collect_creator_fee", Type: (*CollectCreatorFee)(nil),
		},
		{
			Name: "create", Type: (*Create)(nil),
		},
		{
			Name: "extend_account", Type: (*ExtendAccount)(nil),
		},
		{
			Name: "initialize", Type: (*Initialize)(nil),
		},
		{
			Name: "migrate", Type: (*Migrate)(nil),
		},
		{
			Name: "sell", Type: (*Sell)(nil),
		},
		{
			Name: "set_creator", Type: (*SetCreator)(nil),
		},
		{
			Name: "set_metaplex_creator", Type: (*SetMetaplexCreator)(nil),
		},
		{
			Name: "set_params", Type: (*SetParams)(nil),
		},
		{
			Name: "update_global_authority", Type: (*UpdateGlobalAuthority)(nil),
		},
	},
)

func (inst *Instruction) ProgramID() ag_solanago.PublicKey {
	return ProgramID
}

func (inst *Instruction) Accounts() (out []*ag_solanago.AccountMeta) {
	return inst.Impl.(ag_solanago.AccountsGettable).GetAccounts()
}

func (inst *Instruction) Data() ([]byte, error) {
	buf := new(bytes.Buffer)
	if err := ag_binary.NewBorshEncoder(buf).Encode(inst); err != nil {
		return nil, fmt.Errorf("unable to encode instruction: %w", err)
	}
	return buf.Bytes(), nil
}

func (inst *Instruction) TextEncode(encoder *ag_text.Encoder, option *ag_text.Option) error {
	return encoder.Encode(inst.Impl, option)
}

func (inst *Instruction) UnmarshalWithDecoder(decoder *ag_binary.Decoder) error {
	return inst.BaseVariant.UnmarshalBinaryVariant(decoder, InstructionImplDef)
}

func (inst *Instruction) MarshalWithEncoder(encoder *ag_binary.Encoder) error {
	err := encoder.WriteBytes(inst.TypeID.Bytes(), false)
	if err != nil {
		return fmt.Errorf("unable to write variant type: %w", err)
	}
	return encoder.Encode(inst.Impl)
}

func registryDecodeInstruction(accounts []*ag_solanago.AccountMeta, data []byte) (interface{}, error) {
	inst, err := decodeInstruction(accounts, data)
	if err != nil {
		return nil, err
	}
	return inst, nil
}

func decodeInstruction(accounts []*ag_solanago.AccountMeta, data []byte) (*Instruction, error) {
	inst := new(Instruction)
	if err := ag_binary.NewBorshDecoder(data).Decode(inst); err != nil {
		return nil, fmt.Errorf("unable to decode instruction: %w", err)
	}
	if v, ok := inst.Impl.(ag_solanago.AccountsSettable); ok {
		err := v.SetAccounts(accounts)
		if err != nil {
			return nil, fmt.Errorf("unable to set accounts for instruction: %w", err)
		}
	}
	return inst, nil
}

func DecodeInstructions(message *ag_solanago.Message) (instructions []*Instruction, err error) {
	for _, ins := range message.Instructions {
		var programID ag_solanago.PublicKey
		if programID, err = message.Program(ins.ProgramIDIndex); err != nil {
			return
		}
		if !programID.Equals(ProgramID) {
			continue
		}
		var accounts []*ag_solanago.AccountMeta
		if accounts, err = ins.ResolveInstructionAccounts(message); err != nil {
			return
		}
		var insDecoded *Instruction
		if insDecoded, err = decodeInstruction(accounts, ins.Data); err != nil {
			return
		}
		instructions = append(instructions, insDecoded)
	}
	return
}
