package indicatorv2

import (
	"github.com/c9s/bbgo/pkg/datatype/floats"
	"github.com/c9s/bbgo/pkg/types"
)

type CrossType float64

const (
	CrossOver  CrossType = 1.0
	CrossUnder CrossType = -1.0
)

// CrossStream subscribes 2 upstreams, and calculate the cross signal
type CrossStream struct {
	*types.Float64Series

	a, b floats.Slice
}

// Cross creates the CrossStream object:
//
// cross := Cross(fastEWMA, slowEWMA)
func Cross(a, b types.Float64Source) *CrossStream {
	s := &CrossStream{
		Float64Series: types.NewFloat64Series(),
	}
	a.OnUpdate(func(v float64) {
		s.a.Push(v)
		s.calculate()
	})
	b.OnUpdate(func(v float64) {
		s.b.Push(v)
		s.calculate()
	})
	return s
}

func (s *CrossStream) Truncate() {
	s.a = types.ShrinkSlice(s.a, MaxSliceSize, TruncateSize)
	s.b = types.ShrinkSlice(s.b, MaxSliceSize, TruncateSize)
}

func (s *CrossStream) calculate() {
	if s.a.Length() != s.b.Length() {
		return
	}

	current := s.a.Last(0) - s.b.Last(0)
	previous := s.a.Last(1) - s.b.Last(1)

	if previous == 0.0 {
		return
	}

	// cross over or cross under
	if current*previous < 0 {
		if current > 0 {
			s.PushAndEmit(float64(CrossOver))
		} else {
			s.PushAndEmit(float64(CrossUnder))
		}
	}
}
