package wallet

import (
	"context"
	"errors"
	"strings"

	"github.com/tech/sendico/gateway/chain/internal/service/gateway/shared"
	"github.com/tech/sendico/gateway/chain/storage/model"
	"github.com/tech/sendico/pkg/api/routers/gsresponse"
	"github.com/tech/sendico/pkg/merrors"
	"github.com/tech/sendico/pkg/mservice"
	paginationv1 "github.com/tech/sendico/pkg/proto/common/pagination/v1"
	chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
	"go.uber.org/zap"
)

type listManagedWalletsCommand struct {
	deps Deps
}

func NewListManagedWallets(deps Deps) *listManagedWalletsCommand {
	return &listManagedWalletsCommand{deps: deps}
}

func (c *listManagedWalletsCommand) Execute(ctx context.Context, req *chainv1.ListManagedWalletsRequest) gsresponse.Responder[chainv1.ListManagedWalletsResponse] {
	if err := c.deps.EnsureRepository(ctx); err != nil {
		c.deps.Logger.Warn("Repository unavailable", zap.Error(err))
		return gsresponse.Unavailable[chainv1.ListManagedWalletsResponse](c.deps.Logger, mservice.ChainGateway, err)
	}
	filter := model.ManagedWalletFilter{}
	if req != nil {
		filter.OrganizationRef = strings.TrimSpace(req.GetOrganizationRef())
		if req.GetOwnerRefFilter() != nil {
			ownerRef := strings.TrimSpace(req.GetOwnerRefFilter().GetValue())
			filter.OwnerRefFilter = &ownerRef
		}
		if asset := req.GetAsset(); asset != nil {
			filter.Network = shared.ChainKeyFromEnum(asset.GetChain())
			filter.TokenSymbol = strings.TrimSpace(asset.GetTokenSymbol())
		}
		if page := req.GetPage(); page != nil {
			filter.Cursor = strings.TrimSpace(page.GetCursor())
			filter.Limit = page.GetLimit()
		}
	}

	result, err := c.deps.Storage.Wallets().List(ctx, filter)
	if err != nil {
		if errors.Is(err, merrors.ErrNoData) {
			result = &model.ManagedWalletList{}
		} else {
			c.deps.Logger.Warn("Storage list failed", zap.Error(err))
			return gsresponse.Auto[chainv1.ListManagedWalletsResponse](c.deps.Logger, mservice.ChainGateway, err)
		}
	}
	if result == nil {
		result = &model.ManagedWalletList{}
	}

	protoWallets := make([]*chainv1.ManagedWallet, 0, len(result.Items))
	for i := range result.Items {
		protoWallets = append(protoWallets, toProtoManagedWallet(&result.Items[i]))
	}

	resp := &chainv1.ListManagedWalletsResponse{
		Wallets: protoWallets,
		Page:    &paginationv1.CursorPageResponse{NextCursor: result.NextCursor},
	}
	return gsresponse.Success(resp)
}
