package label

import (
	"reflect"
)

type State int

const (
	StateFailed State = iota
	StateSkipped
	StateSucceed
	StatePending
)

type object[T any] struct {
	c        T
	desc     string
	labelSet LabelSet

	state State
	err   error
}

func (c *object[T]) Desc(desc string) Object[T] {
	c.desc = desc
	return c
}

func (c *object[T]) Labels(ls Labels) Object[T] {
	c.labelSet.Merge(ls)
	return c
}

func (c *object[T]) GetDesc() string {
	return c.desc
}
func (c *object[T]) GetLabels() Labels {
	return c.labelSet
}

func (c *object[T]) GetState() State {
	return c.state
}

func (c *object[T]) Get() T {
	return c.c
}

func (c *object[T]) Fail(err error) {
	c.state = StateFailed
	c.err = err
}

func (c *object[T]) Skip() {
	c.state = StateSkipped
}

func (c *object[T]) Succeed() {
	c.state = StateSucceed
}

func (c *object[T]) Error() error {
	return c.err
}

func (o *object[T]) DeepCopy() Object[T] {
	c := o.Get()

	val := reflect.ValueOf(c).Elem()
	nc := reflect.New(val.Type())
	nc.Elem().Set(val)

	s := LabelSet{}
	for k, v := range o.labelSet {
		s[k] = v
	}
	return &object[T]{
		c:        nc.Interface().(T),
		desc:     o.desc,
		labelSet: s,
		state:    StatePending,
	}

}

func New[T any](obj T, desc string, ls ...Label) Object[T] {
	s := LabelSet{}
	for _, l := range ls {
		s[l.Key()] = l.Value()
	}
	return &object[T]{
		c:        obj,
		desc:     desc,
		labelSet: s,
		state:    StatePending,
	}
}

func MatchState[T any](o Object[T], s State) bool {
	return o.GetState() == s
}
