package middleware

import (
	"reflect"

	"github.com/ngaut/log"
	"github.com/pingcap/schrodinger/notifiermgr/event"
)

func combineDriver(configPtr *interface{}) Middleware {
	input := make(chan event.Event)
	output := make(chan event.Event)

	middlewareNames, ok := (*configPtr).([]interface{})
	if !ok {
		log.Errorf("config of combine is not a list of string but %T", *configPtr)
	}

	go func() {
		middlewares := make([]Middleware, len(middlewareNames))
		inited := false

		for ev := range input {
			if !inited {
				err := loadFromNames(&middlewares, middlewareNames)
				if err != nil {
					log.Error(err)
					return
				}

				go func() {
					cases := make([]reflect.SelectCase, len(middlewares))
					for i, middleware := range middlewares {
						cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf((*middleware).Output)}
					}

					for {
						_, value, ok := reflect.Select(cases)
						if !ok {
							continue
						}
						event, ok := value.Interface().(event.Event)
						if !ok {
							log.Error("Convert type in combine middleware failed")
							continue
						}
						output <- event
					}
				}()
				inited = true
			}

			for _, middleware := range middlewares {
				if middleware == nil {
					log.Error("Middleware in combine part is nil")
					return
				}
				(*middleware).Input <- ev
			}
		}
	}()

	return &RealMiddleware{
		input,
		output,
	}
}
