package flow

import (
	"fmt"

	"go.starlark.net/starlark"
)

const (
	futureName = "future"
	futureType = "future"
)

var (
	_ starlark.Callable = (*FutureType)(nil)
)

type Future interface {
	// TODO: support getting values out of it
	Get() error

	Unwrap() any
}

// TODO implement IsReady() bool?
// TODO implement a way to get with a timeout? Or just use selector?

type FutureType struct {
	f Future
}

func (f *FutureType) Unwrap() any {
	return f.f.Unwrap()
}

func (f *FutureType) String() string {
	return fmt.Sprintf("<%s>", f.Name())
}

func (f *FutureType) Type() string {
	return futureType
}

func (f *FutureType) Freeze() {
}

func (f *FutureType) Truth() starlark.Bool {
	return starlark.True
}

func (f *FutureType) Hash() (uint32, error) {
	return 0, fmt.Errorf("unhashable: %s", f.Type())
}

func (f *FutureType) Name() string {
	return futureName
}

func (f *FutureType) CallInternal(thread *starlark.Thread, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
	if len(args) > 0 {
		return nil, fmt.Errorf("%s: unexpected positional arguments", f.Name())
	}
	if len(kwargs) > 0 {
		return nil, fmt.Errorf("%s: unexpected keyword arguments", f.Name())
	}
	err := f.f.Get()
	if err != nil {
		return nil, err
	}
	return starlark.None, nil
}
