package client

import (
	"context"
	"fmt"

	"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
	"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
	"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
	"github.com/nspcc-dev/neo-go/pkg/util"
	"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
)

type waiterClient struct {
	c *Client
}

func (w *waiterClient) Context() context.Context {
	return context.Background()
}

func (w *waiterClient) GetApplicationLog(hash util.Uint256, trig *trigger.Type) (*result.ApplicationLog, error) {
	return w.c.GetApplicationLog(hash, trig)
}

func (w *waiterClient) GetBlockCount() (uint32, error) {
	return w.c.BlockCount()
}

func (w *waiterClient) GetVersion() (*result.Version, error) {
	return w.c.GetVersion()
}

// WaitTxHalt waits until transaction with the specified hash persists on the blockchain.
// It also checks execution result to finish in HALT state.
func (c *Client) WaitTxHalt(ctx context.Context, p InvokeRes) error {
	w, err := waiter.NewPollingBased(&waiterClient{c: c})
	if err != nil {
		return fmt.Errorf("create tx waiter: %w", err)
	}

	res, err := w.WaitAny(ctx, p.VUB, p.Hash)
	if err != nil {
		return fmt.Errorf("wait until tx persists: %w", err)
	}

	if res.VMState.HasFlag(vmstate.Halt) {
		return nil
	}
	return wrapFrostFSError(&notHaltStateError{state: res.VMState.String(), exception: res.FaultException})
}