package zltx

import (
	"ai_scheduler/internal/config"

	toolZoarb "ai_scheduler/internal/domain/tools/zltx/order_after_reseller_batch"
	"ai_scheduler/internal/domain/workflow/runtime"
	"ai_scheduler/internal/entitys"
	"ai_scheduler/internal/pkg/util"
	"context"
	"encoding/json"
	"errors"

	"github.com/cloudwego/eino/compose"
	"github.com/cloudwego/eino/schema"
)

func init() {
	runtime.Register("zltx.orderAfterSaleResellerBatch", func(d *runtime.Deps) (runtime.Workflow, error) {
		return &orderAfterSaleResellerBatch{cfg: d.Conf.Tools.ZltxOrderAfterSaleResellerBatch}, nil
	})
}

type orderAfterSaleResellerBatch struct {
	cfg config.ToolConfig
}

// 工作流入参
type OrderAfterSaleResellerBatchWorkflowInput struct {
	Ch              chan entitys.Response                // 响应通道
	UserInput       string                               // 用户输入文本
	FileContent     string                               // 文件解析结果
	UserHistory     entitys.ChatHis                      // 用户对话历史
	ParameterResult string                               // 参数解析结果
	Data            *OrderAfterSaleResellerBatchNodeData // 节点所需参数
}

// 节点所需参数
type OrderAfterSaleResellerBatchNodeData struct {
	OrderNumber       []string `json:"orderNumber"`       // 订单号
	AfterType         string   `json:"afterType"`         // 处理方式 1.退款 2.扣款
	AfterSalesPrice   string   `json:"afterSalesPrice"`   // 售后金额
	AfterSalesReason  string   `json:"afterSalesReason"`  // 售后原因
	ResponsibleType   string   `json:"responsibleType"`   // 费用承担者 1.供应商 2.商务 3.公司 4.无
	ResponsiblePerson string   `json:"responsiblePerson"` // 费用承担供应商
}

// 工作流出参
type OrderAfterSaleResellerBatchWorkflowOutput struct {
	Code int                                `json:"code"`
	Msg  string                             `json:"msg"`
	Data []*OrderAfterSaleResellerBatchData `json:"data"`
}

type OrderAfterSaleResellerBatchData struct {
	OrderType         int            `json:"orderType"`
	OrderNumber       string         `json:"orderNumber"`
	OrderAmount       float64        `json:"orderAmount"`
	OrderPrice        float64        `json:"orderPrice"`
	SignCompany       int            `json:"signCompany"`
	OrderQuantity     int            `json:"orderQuantity"`
	ResellerID        int            `json:"resellerId"`
	ResellerName      string         `json:"resellerName"`
	OurProductID      int            `json:"ourProductId"`
	OurProductTitle   string         `json:"ourProductTitle"`
	Account           []string       `json:"account"`
	Platforms         map[int]string `json:"platforms"`
	AfterType         int            `json:"afterType"`         // 处理方式 1.退款 2.扣款
	Remark            string         `json:"remark"`            // 售后原因
	AfterAmount       float64        `json:"afterAmount"`       // 售后金额
	ResponsibleType   int            `json:"responsibleType"`   // 费用承担者 1.供应商 2.商务 3.公司 4.无
	ResponsiblePerson string         `json:"responsiblePerson"` // 费用承担供应商
	IsExistsAfterSale bool           `json:"isExistsAfterSale"` // 是否已存在售后
	CreateTime        int            `json:"createTime"`        // 创建时间
}

// ID 返回工作流唯一标识
func (o *orderAfterSaleResellerBatch) ID() string { return "zltx.orderAfterSaleResellerBatch" }

// Invoke 调用原有编排工作流并规范化输出
func (o *orderAfterSaleResellerBatch) Invoke(ctx context.Context, rec *runtime.WorkflowArgs) (map[string]any, error) {
	// 构建工作流
	chain, err := o.buildWorkflow(ctx)
	if err != nil {
		return nil, err
	}

	input := &OrderAfterSaleResellerBatchWorkflowInput{
		Ch:              rec.Ch,
		UserInput:       rec.UserContent.Text,
		FileContent:     "",
		UserHistory:     rec.ChatHis,
		ParameterResult: rec.Match.Parameters,
	}

	// 将 Input 注入 Context
	ctx = context.WithValue(ctx, workflowInputContextKey{}, input)

	// 工作流过程输出，不关注最终输出
	_, err = chain.Invoke(ctx, input)
	if err != nil {
		return nil, err
	}

	// 工作流 callback

	// 不关心输出，全部在途中输出
	return nil, nil
}

var ErrInvalidOrderNumbers = errors.New("orderNumber 不能为空")

// contextKey 用于在 Context 中传递 WorkflowInput
type workflowInputContextKey struct{}

// buildWorkflow 构建工作流
func (o *orderAfterSaleResellerBatch) buildWorkflow(ctx context.Context) (compose.Runnable[*OrderAfterSaleResellerBatchWorkflowInput, *OrderAfterSaleResellerBatchWorkflowOutput], error) {
	// 定义工作流、出入参
	c := compose.NewChain[*OrderAfterSaleResellerBatchWorkflowInput, *OrderAfterSaleResellerBatchWorkflowOutput]()

	// 1.llm 推断参数 （若需要）
	c.AppendLambda(compose.InvokableLambda(func(_ context.Context, in *OrderAfterSaleResellerBatchWorkflowInput) (*schema.Message, error) {
		// 已推断完，直接使用
		parameters := in.ParameterResult
		return &schema.Message{Content: parameters}, nil
	}))

	// 2.参数解析为结构体
	c.AppendLambda(compose.MessageParser(
		schema.NewMessageJSONParser[*OrderAfterSaleResellerBatchNodeData](&schema.MessageJSONParseConfig{
			ParseFrom:    schema.MessageParseFromContent,
			ParseKeyPath: "", // 如果仅需要 parse 子字段，可用 "key.sub.grandsub"
		}),
	))

	// 3.参数校验 & 传递 Input
	// 注意：为了在后续节点访问 WorkflowInput，这里使用闭包或 Context 传递。
	// Eino Chain 节点间传递的是返回值。这里我们修改节点签名，将 input 一路传下去，或者使用 context。
	// 由于 Eino Chain 是强类型的，这里选择让 Parser 返回的数据结构包含原始 input，或者我们在 Parser 后重新组合。
	// 但最简单的方法是使用 Context 存储 Input (如果 Eino 支持 Context 传递)。Eino 的 Invoke 接受 ctx。
	// 但 Eino Chain 的设计是数据流驱动。
	// 修正方案：修改中间节点的数据结构，或者使用闭包捕获（但闭包捕获的是 build 时的变量，无法捕获运行时 input）。
	// 正确做法：Chain 的节点入参必须是上一个节点的出参。
	// 我们可以把 Parser 的输入改为 Input，输出改为一个包含 Input 和 ParsedData 的结构。
	// 但这里为了最小改动，我们利用 Context 来传递 Input 引用（这在 Eino 中是可行的，因为 ctx 会贯穿整个 Invoke）。
	// 更好的做法是重构 Chain 的数据流，但在保持逻辑不变的前提下，Context 是最快解法。

	// 为了线程安全，我们在第一个节点把 Input 放入 Context？不行，Chain.Invoke(ctx, input) 的 ctx 是外部传入的。
	// Eino 允许 Lambda 修改 Context 吗？通常不允许。

	// 让我们重新审视数据流：
	// Input -> Lambda1 -> Message -> Parser -> NodeData -> Lambda4 -> ToolResp -> Lambda5 -> Output
	// Lambda4 需要 Input.Ch 来发 Loading。
	// Lambda5 需要 Input.Ch 来发 Log/Json，还需要 NodeData。

	// 根本问题是：中间节点丢失了 Input 信息。
	// 解决方案：使用一个聚合结构体在 Chain 中传递。

	// 由于要大改数据流比较复杂，这里使用一种技巧：
	// 在 Invoke 时，构造一个带有 Input 信息的 Context 传入。
	// 这样每个节点都能从 Context 拿到 Input。

	// 重新实现 buildWorkflow 以支持 Context 传递
	return o.buildWorkflowWithContext(ctx)
}

func (o *orderAfterSaleResellerBatch) buildWorkflowWithContext(ctx context.Context) (compose.Runnable[*OrderAfterSaleResellerBatchWorkflowInput, *OrderAfterSaleResellerBatchWorkflowOutput], error) {
	c := compose.NewChain[*OrderAfterSaleResellerBatchWorkflowInput, *OrderAfterSaleResellerBatchWorkflowOutput]()

	// 0. Context 注入节点 (Trick: 利用第一个节点将 Input 注入 Context，但 Eino Chain 无法修改 Context 传递给下游)
	// 实际上，我们可以在 Invoke 调用前，在外部包装 Context。
	// 所以这里不需要额外的节点，只需要在 Invoke 时处理。
	// 但 Invoke 是由 Chain 提供的，我们只能控制传入的 ctx。
	// 见下文 Invoke 方法的修改。

	// 1.llm 推断参数
	c.AppendLambda(compose.InvokableLambda(func(ctx context.Context, in *OrderAfterSaleResellerBatchWorkflowInput) (*schema.Message, error) {
		return &schema.Message{Content: in.ParameterResult}, nil
	}))

	// 2.参数解析
	c.AppendLambda(compose.MessageParser(
		schema.NewMessageJSONParser[*OrderAfterSaleResellerBatchNodeData](&schema.MessageJSONParseConfig{
			ParseFrom: schema.MessageParseFromContent,
		}),
	))

	// 3.参数校验
	c.AppendLambda(compose.InvokableLambda(func(ctx context.Context, in *OrderAfterSaleResellerBatchNodeData) (*OrderAfterSaleResellerBatchNodeData, error) {
		if len(in.OrderNumber) == 0 {
			return nil, ErrInvalidOrderNumbers
		}
		// 将解析后的 Data 存入 Input (通过 Context 获取 Input)
		input := ctx.Value(workflowInputContextKey{}).(*OrderAfterSaleResellerBatchWorkflowInput)
		input.Data = in // 这里修改 Input 是安全的，因为 Input 是请求维度的引用
		return in, nil
	}))

	// 4.工具调用
	c.AppendLambda(compose.InvokableLambda(func(ctx context.Context, in *OrderAfterSaleResellerBatchNodeData) (*toolZoarb.OrderAfterSaleResellerBatchResponse, error) {
		input := ctx.Value(workflowInputContextKey{}).(*OrderAfterSaleResellerBatchWorkflowInput)

		entitys.ResLoading(input.Ch, o.ID(), "数据拉取中")
		toolRes, err := toolZoarb.Call(ctx, o.cfg, in.OrderNumber)
		entitys.ResLog(input.Ch, o.ID(), "数据拉取完成")

		return toolRes, err
	}))

	// 5.结果数据映射
	c.AppendLambda(compose.InvokableLambda(func(ctx context.Context, in *toolZoarb.OrderAfterSaleResellerBatchResponse) (*OrderAfterSaleResellerBatchWorkflowOutput, error) {
		return o.dataMapping(ctx, in)
	}))

	return c.Compile(ctx)
}

// 结果数据映射
func (o *orderAfterSaleResellerBatch) dataMapping(ctx context.Context, in *toolZoarb.OrderAfterSaleResellerBatchResponse) (*OrderAfterSaleResellerBatchWorkflowOutput, error) {
	input := ctx.Value(workflowInputContextKey{}).(*OrderAfterSaleResellerBatchWorkflowInput)

	entitys.ResLog(input.Ch, o.ID(), "数据整理中")

	toolResp := &OrderAfterSaleResellerBatchWorkflowOutput{
		Code: in.Code,
		Msg:  in.Error,
		Data: make([]*OrderAfterSaleResellerBatchData, 0, len(in.Data.Data)),
	}

	// 转换数据
	for _, item := range in.Data.Data {
		// 处理方式
		afterType := util.StringToInt(input.Data.AfterType)
		if afterType == 0 {
			afterType = 1 // 默认退款
		}
		// 费用承担者
		responsibleType := util.StringToInt(input.Data.ResponsibleType)
		if responsibleType == 0 {
			responsibleType = 4 // 默认无
		}
		// 售后金额
		afterSalesPrice := util.StringToFloat64(input.Data.AfterSalesPrice)
		if afterSalesPrice == 0 {
			afterSalesPrice = item.OrderPrice
		}

		toolResp.Data = append(toolResp.Data, &OrderAfterSaleResellerBatchData{
			OrderType:         item.OrderType,
			OrderNumber:       item.OrderNumber,
			OrderAmount:       item.OrderAmount,
			OrderPrice:        item.OrderPrice,
			SignCompany:       item.SignCompany,
			OrderQuantity:     item.OrderQuantity,
			ResellerID:        item.ResellerID,
			ResellerName:      item.ResellerName,
			OurProductID:      item.OurProductID,
			OurProductTitle:   item.OurProductTitle,
			Account:           item.Account,
			Platforms:         item.Platforms,
			AfterType:         afterType,
			Remark:            input.Data.AfterSalesReason,
			AfterAmount:       afterSalesPrice,
			ResponsibleType:   responsibleType,
			ResponsiblePerson: input.Data.ResponsiblePerson,
		})
	}

	// 追加扩展数据
	for _, item := range toolResp.Data {
		if extItem, ok := in.Data.ExtData[item.OrderNumber]; ok {
			item.IsExistsAfterSale = item.OrderType > 100 // 102 批充&已售后
			item.CreateTime = extItem.SerialCreateTime
		}
	}

	toolRespJson, _ := json.Marshal(toolResp)
	entitys.ResJson(input.Ch, o.ID(), string(toolRespJson))

	return toolResp, nil
}
