package flow

import (
	"git.sxidc.com/go-tools/utils/pipeline/component"
	"github.com/mitchellh/mapstructure"
	"github.com/pkg/errors"
)

const (
	TypeBi = "bi"
)

const (
	BiLeft  = "bi_left"
	BiRight = "bi_right"
)

type BiBuildParams struct {
	Components []SubComponentBuildParams `mapstructure:"components" structs:"components"`
}

func (params *BiBuildParams) Check() error {
	if params.Components == nil || len(params.Components) == 0 {
		return errors.New(TypeBi + "流没有包含任何组件")
	}

	subComponentMap := make(map[string]bool)
	for _, componentParams := range params.Components {
		err := componentParams.Check(TypeBi)
		if err != nil {
			return err
		}

		_, ok := subComponentMap[componentParams.Name]
		if ok {
			return errors.New("该流程中存在同名的组件: " + componentParams.Name)
		}

		subComponentMap[componentParams.Name] = true
	}

	return nil
}

type BiRunParams struct {
	IsBi        bool `mapstructure:"is_bi" structs:"is_bi"`
	LeftParams  any  `mapstructure:"left_params" structs:"left_params"`
	RightParams any  `mapstructure:"right_params" structs:"right_params"`
}

func (params *BiRunParams) Check() error {
	if params.LeftParams == nil {
		return errors.New(TypeBi + "没有传递左参数")
	}

	if params.LeftParams == nil {
		return errors.New(TypeBi + "没有传递右参数")
	}

	return nil
}

type Bi struct {
	component.BaseComponent
	Components []component.Component
}

func (f *Bi) Run(globalRunParams *component.GlobalRunParams, dynamicParams map[string]any) (any, error) {
	return f.OnRun(globalRunParams, dynamicParams,
		func(globalRunParams *component.GlobalRunParams, dynamicParams map[string]any) (any, error) {
			params := new(BiRunParams)
			err := mapstructure.Decode(dynamicParams, params)
			if err != nil {
				return nil, errors.New(TypeBi + "流程运行时参数Decode失败: " + err.Error())
			}

			err = params.Check()
			if err != nil {
				return nil, err
			}

			result, err := f.runSubComponents(globalRunParams, dynamicParams, params.LeftParams, params.RightParams)
			if err != nil {
				return nil, err
			}

			if !params.IsBi {
				return result, nil
			}

			result, err = f.runSubComponents(globalRunParams, dynamicParams, params.RightParams, params.LeftParams)
			if err != nil {
				return nil, err
			}

			return result, nil
		})
}

func (f *Bi) runSubComponents(globalRunParams *component.GlobalRunParams, dynamicParams map[string]any,
	leftParams any, rightParams any) (any, error) {
	var result any

	for _, subComponent := range f.Components {
		subDynamicParamsMap := make(map[string]any)
		subDynamicParams, ok := dynamicParams[subComponent.GetName()]
		if ok {
			innerSubDynamicParamsMap, ok := subDynamicParams.(map[string]any)
			if !ok {
				return nil, errors.New(TypeBi + "流程" + f.GetName() + "的子组件" + subComponent.GetName() + "动态参数类型错误")
			}

			subDynamicParamsMap = innerSubDynamicParamsMap
		}

		subDynamicParamsMap[BiLeft] = leftParams
		subDynamicParamsMap[BiRight] = rightParams

		innerResult, err := subComponent.Run(globalRunParams, subDynamicParamsMap)
		if err != nil {
			return nil, err
		}

		result = innerResult
	}

	return result, nil
}

type BiBuilder struct{}

func (builder *BiBuilder) ProductType() string {
	return TypeBi
}

func (builder *BiBuilder) Build(name string, buildParams map[string]any, runParams map[string]any) (component.Component, error) {
	if buildParams == nil || len(buildParams) == 0 {
		return nil, errors.New(TypeBi + "流程没有传递构建参数")
	}

	flowBuildParams := new(BiBuildParams)
	err := mapstructure.Decode(buildParams, flowBuildParams)
	if err != nil {
		return nil, errors.New(TypeBi + "流程构建参数Decode失败: " + err.Error())
	}

	err = flowBuildParams.Check()
	if err != nil {
		return nil, err
	}

	subComponents := make([]component.Component, 0)
	for _, componentParams := range flowBuildParams.Components {
		subComponent, err := componentParams.BuildComponent()
		if err != nil {
			return nil, err
		}

		subComponents = append(subComponents, subComponent)
	}

	return &Bi{
		BaseComponent: *component.NewBaseComponent(TypeBi, name, runParams),
		Components:    subComponents,
	}, nil
}