package keeper

import (
	"fmt"

	"cosmossdk.io/collections"
	"cosmossdk.io/core/address"
	corestore "cosmossdk.io/core/store"
	"github.com/cosmos/cosmos-sdk/codec"
	 <%= if (isIBC) { %> ibckeeper "github.com/cosmos/ibc-go/v10/modules/core/keeper" <% } %>

	"<%= modulePath %>/x/<%= moduleName %>/types"
)

type Keeper struct {
	storeService corestore.KVStoreService
	cdc          codec.Codec
	addressCodec address.Codec
	// Address capable of executing a MsgUpdateParams message.
	// Typically, this should be the x/gov module account.
	authority []byte

	Schema collections.Schema
	Params collections.Item[types.Params]
    <%= if (isIBC) { %>
	Port   collections.Item[string]

	ibcKeeperFn func() *ibckeeper.Keeper <% } %>
	<%= for (dependency) in dependencies { %>
    <%= toVariableName(dependency.KeeperName()) %> types.<%= dependency.KeeperName() %><% } %>
}

func NewKeeper(
	storeService corestore.KVStoreService,
	cdc codec.Codec,
	addressCodec address.Codec,
	authority []byte,<%= if (isIBC) { %>
	ibcKeeperFn func() *ibckeeper.Keeper,<% } %>
    <%= for (dependency) in dependencies { %>
    <%= toVariableName(dependency.KeeperName()) %> types.<%= dependency.KeeperName() %>,<% } %>
) Keeper {
	if _, err := addressCodec.BytesToString(authority); err != nil {
		panic(fmt.Sprintf("invalid authority address %s: %s", authority, err))
	}

	sb := collections.NewSchemaBuilder(storeService)

	k := Keeper{
		storeService: storeService,
		cdc:          cdc,
		addressCodec: addressCodec,
		authority:    authority,
		<%= for (dependency) in dependencies { %>
		<%= toVariableName(dependency.KeeperName()) %>: <%= toVariableName(dependency.KeeperName()) %>,<% } %><%= if (isIBC) { %>
		ibcKeeperFn:  ibcKeeperFn,
		Port:         collections.NewItem(sb, types.PortKey, "port", collections.StringValue),<% } %>
		Params:       collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)),
	}

	schema, err := sb.Build()
	if err != nil {
		panic(err)
	}
	k.Schema = schema

	return k
}

// GetAuthority returns the module's authority.
func (k Keeper) GetAuthority() []byte {
	return k.authority
}
