package flow

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

const (
	TypeRange = "range"
)

const (
	RangeIndex     = "range_index"
	RangeOnceValue = "range_once_value"
)

type RangeBuildParams struct {
	Values       []any                    `mapstructure:"values" structs:"values"`
	SubComponent *SubComponentBuildParams `mapstructure:"sub" structs:"sub"`
}

func (params *RangeBuildParams) Check() error {
	if params.SubComponent == nil {
		return errors.New(TypeRange + "流程的子组件参数为空")
	}

	err := params.SubComponent.Check(TypeRange)
	if err != nil {
		return err
	}

	return nil
}

type Range struct {
	component.BaseComponent
	Values       []any
	SubComponent component.Component
}

func (f *Range) 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) {
			lastResult := globalRunParams.GetLastResult()

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

				subDynamicParamsMap = innerSubDynamicParamsMap
			}

			if f.Values == nil || len(f.Values) == 0 {
				return lastResult, nil
			}

			var result any
			for index, value := range f.Values {
				subDynamicParamsMap[RangeIndex] = index
				subDynamicParamsMap[RangeOnceValue] = value

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

				result = innerResult
			}

			return result, nil
		})
}

type RangeBuilder struct{}

func (builder *RangeBuilder) ProductType() string {
	return TypeRange
}

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

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

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

	subFlow, err := flowBuildParams.SubComponent.BuildComponent()
	if err != nil {
		return nil, err
	}

	return &Range{
		BaseComponent: *component.NewBaseComponent(TypeLoop, name, runParams),
		Values:        flowBuildParams.Values,
		SubComponent:  subFlow,
	}, nil
}