package verifreg

import (
	"golang.org/x/xerrors"

	"github.com/filecoin-project/go-address"
	"github.com/filecoin-project/go-state-types/abi"

	"github.com/filecoin-project/go-state-types/cbor"
{{range .versions}}
    {{if (le . 7)}}
	    builtin{{.}} "github.com/filecoin-project/specs-actors{{import .}}actors/builtin"
	{{else}}
        builtin{{.}} "github.com/filecoin-project/go-state-types/builtin"
    {{end}}
{{end}}

	"github.com/filecoin-project/lotus/chain/actors/adt"
	"github.com/filecoin-project/lotus/chain/actors"
	"github.com/filecoin-project/lotus/chain/types"
)

var (
	Address = builtin{{.latestVersion}}.VerifiedRegistryActorAddr
	Methods = builtin{{.latestVersion}}.MethodsVerifiedRegistry
)

func Load(store adt.Store, act *types.Actor) (State, error) {
	if name, av, ok := actors.GetActorMetaByCode(act.Code); ok {
       if name != actors.VerifregKey {
          return nil, xerrors.Errorf("actor code is not verifreg: %s", name)
       }

       switch av {
            {{range .versions}}
                {{if (ge . 8)}}
                case actors.Version{{.}}:
                     return load{{.}}(store, act.Head)
                 {{end}}
            {{end}}
       }
	}

	switch act.Code {
{{range .versions}}
    {{if (le . 7)}}
        case builtin{{.}}.VerifiedRegistryActorCodeID:
            return load{{.}}(store, act.Head)
    {{end}}
{{end}}
	}

	return nil, xerrors.Errorf("unknown actor code %s", act.Code)
}

func MakeState(store adt.Store, av actors.Version, rootKeyAddress address.Address) (State, error) {
	switch av {
{{range .versions}}
	case actors.Version{{.}}:
		return make{{.}}(store, rootKeyAddress)
{{end}}
}
	return nil, xerrors.Errorf("unknown actor version %d", av)
}

type State interface {
	cbor.Marshaler

	RootKey() (address.Address, error)
	VerifiedClientDataCap(address.Address) (bool, abi.StoragePower, error)
	VerifierDataCap(address.Address) (bool, abi.StoragePower, error)
	RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error)
	ForEachVerifier(func(addr address.Address, dcap abi.StoragePower) error) error
	ForEachClient(func(addr address.Address, dcap abi.StoragePower) error) error
	GetState() interface{}
}