package framework

import (
	"fmt"
)

type InputProviderCreator func(
	eventReceiver EventReceiver,
	config ConfigData) (pInputProvider any, err error)

type InputProviderManager struct {
	eventReceiver EventReceiver
	creators      map[InputProviderMeta]InputProviderCreator
}

func NewInputProviderManager(eventReceiver EventReceiver) *InputProviderManager {
	return &InputProviderManager{
		eventReceiver: eventReceiver,
		creators:      make(map[InputProviderMeta]InputProviderCreator),
	}
}

func (this *InputProviderManager) Register(meta InputProviderMeta, creator InputProviderCreator) error {
	_, ok := this.creators[meta]
	if ok {
		this.eventReceiver.OnEvent(
			EventInputProviderManagerRegisterCreatorDuplicated,
			EventDataWithName("InputMeta", CloneableString(meta.String())))
		return fmt.Errorf("[InputProviderManager.Register] meta `%s` already exists", meta.String())
	}
	this.creators[meta] = creator
	this.eventReceiver.OnEvent(
		EventInputProviderManagerRegisterCreatorOk,
		EventDataWithName("InputMeta", CloneableString(meta.String())))
	return nil
}

func (this *InputProviderManager) NewInput(
	meta InputProviderMeta,
	config ConfigData) (any, error) {

	creator, ok := this.creators[meta]
	if !ok {
		this.eventReceiver.OnEvent(
			EventInputProviderManagerCreatorNotFound,
			EventDataWithName("InputMeta", CloneableString(meta.String())))
		return nil, fmt.Errorf("[InputProviderManager.NewInput] meta `%s` does not exist", meta.String())
	}
	input, err := creator(this.eventReceiver, config)
	if err != nil {
		return nil, err
	}
	this.eventReceiver.OnEvent(
		EventInputProviderManagerCreatedInput,
		EventDataWithName("InputMeta", CloneableString(meta.String())))
	switch meta.InterfaceVersion {
	case InputInterfaceV1IdStr:
		if _, ok := input.(InputInterfaceV1); !ok {
			return nil, fmt.Errorf("[InputProviderManager.NewInput] input `%s` does not implement InputInterfaceV1", meta.String())
		}
	case InputInterfaceV2IdStr:
		if _, ok := input.(InputInterfaceV2); !ok {
			return nil, fmt.Errorf("[InputProviderManager.NewInput] input `%s` does not implement InputInterfaceV2", meta.String())
		}
	}
	return input, nil
}

func NewDefaultInputProviderManager(eventReceiver EventReceiver) (*InputProviderManager, error) {
	manager := NewInputProviderManager(eventReceiver)

	err := manager.Register(
		InputProviderMockEmptyMeta,
		func(eventReceiver EventReceiver, _ ConfigData) (any, error) {
			return NewInputProviderMockEmpty(eventReceiver), nil
		},
	)
	if err != nil {
		return nil, err
	}

	err = manager.Register(
		InputProviderMockV1Meta,
		func(eventReceiver EventReceiver, config ConfigData) (any, error) {
			cfg, ok := config.(*InputProviderMockConfigV1)
			if !ok {
				return nil, fmt.Errorf("[InputProviderMockConfigV1] config type unmatched")
			}
			return NewInputProviderMockV1(eventReceiver, cfg), nil
		},
	)
	if err != nil {
		return nil, err
	}

	return manager, nil
}
