package recharge

import (
	"ai_scheduler/internal/config"
	errorcode "ai_scheduler/internal/data/error"
	toolManager "ai_scheduler/internal/domain/tools"
	"ai_scheduler/internal/domain/tools/common/excel_generator"
	"ai_scheduler/internal/domain/tools/recharge/statistics_ours_product"
	"ai_scheduler/internal/domain/workflow/runtime"
	"ai_scheduler/internal/pkg/lsxd"
	"ai_scheduler/internal/pkg/utils_oss"
	"ai_scheduler/pkg"
	"ai_scheduler/utils"
	"context"
	"errors"
	"fmt"
	"math/rand"
	"path/filepath"
	"sort"
	"strconv"
	"time"

	"github.com/cloudwego/eino/compose"
	"github.com/go-kratos/kratos/v2/log"
)

const WorkflowIDStatisticsOursProduct = "recharge.statisticsOursProduct"

func init() {
	runtime.Register(WorkflowIDStatisticsOursProduct, func(d *runtime.Deps) (runtime.Workflow, error) {
		return &statisticsOursProduct{
			cfg:         d.Conf,
			toolManager: d.ToolManager,
			ossClient:   d.Repos.OssClient,
			rdb:         d.Repos.Rdb,
			lsxdLogin:   d.Component.LSXDLogin,
		}, nil
	})
}

type statisticsOursProduct struct {
	cfg         *config.Config
	toolManager *toolManager.Manager
	ossClient   *utils_oss.Client
	rdb         *utils.Rdb
	lsxdLogin   *lsxd.Login
}

type StatisticsOursProductWorkflowInput struct {
	Time time.Time `json:"time"`
}

type StatisticsOursProductWorkflowOutput struct {
	Path string     `json:"path"`
	Url  string     `json:"url"`
	Data [][]string `json:"data"`
	Desc string     `json:"desc"`
}

func (w *statisticsOursProduct) ID() string { return WorkflowIDStatisticsOursProduct }

func (w *statisticsOursProduct) Invoke(ctx context.Context, args *runtime.WorkflowArgs) (map[string]any, error) {
	// 构建工作流
	runnable, err := w.buildWorkflow(ctx)
	if err != nil {
		return nil, err
	}

	// 获取参数时间
	input := &StatisticsOursProductWorkflowInput{
		Time: args.Args["now"].(time.Time),
	}

	// 工作流过程调用
	output, err := runnable.Invoke(ctx, input)
	if err != nil {
		fmt.Println("Invoke err:", err)
		errStr := err.Error()
		if u := errors.Unwrap(err); u != nil {
			errStr = u.Error()
		}
		return nil, errorcode.WorkflowErr(errStr)
	}

	return output, nil
}

type StatisticsOursProductContext struct {
	Time        time.Time
	StartTime   string
	EndTime     string
	Title       string
	ProductData []statistics_ours_product.StatisticsOursProductItem
	ImgUrl      string
	ExcelData   [][]string
	TotalLoss   float64
}

func (w *statisticsOursProduct) buildWorkflow(ctx context.Context) (compose.Runnable[*StatisticsOursProductWorkflowInput, map[string]any], error) {
	c := compose.NewChain[*StatisticsOursProductWorkflowInput, map[string]any]()

	// 1. 参数整理
	c.AppendLambda(compose.InvokableLambda(w.formatContext))

	// 2. 调用工具统计我们的商品
	c.AppendLambda(compose.InvokableLambda(w.callStatisticsTool))

	// 3. 生成 Excel 并转图片上传
	c.AppendLambda(compose.InvokableLambda(w.generateExcelAndUpload))

	// 4. 转map输出
	c.AppendLambda(compose.InvokableLambda(w.convertToMap))

	return c.Compile(ctx)
}

// formatContext 整理上下文参数
func (w *statisticsOursProduct) formatContext(ctx context.Context, input *StatisticsOursProductWorkflowInput) (*StatisticsOursProductContext, error) {
	startTime := input.Time.Format("2006010200")
	// startTime := "2025010500"
	endTime := input.Time.Format("2006010215")
	endTimeStr := input.Time.Format("1.2号15点")

	return &StatisticsOursProductContext{
		Time:      time.Now(),
		StartTime: startTime,
		EndTime:   endTime,
		Title:     fmt.Sprintf("截止 %s 电商系统亏损100以上我们的商品统计", endTimeStr),
	}, nil
}

func (w *statisticsOursProduct) callStatisticsTool(ctx context.Context, state *StatisticsOursProductContext) (*StatisticsOursProductContext, error) {
	// 前置获取登录token
	token := w.lsxdLogin.GetToken(ctx)
	if token == "" {
		return nil, fmt.Errorf("登录token为空")
	}

	req := statistics_ours_product.StatisticsOursProductRequest{
		Token:  token,
		Page:   1,
		Limit:  100, // 仅取前100条
		Serial: []string{state.StartTime, state.EndTime},
	}

	dataList, err := w.toolManager.Recharge.StatisticsOursProduct.Call(ctx, req)
	if err != nil {
		log.Errorf("调用统计我们的商品工具失败: %v", err)
		return nil, fmt.Errorf("获取统计我们的商品数据失败")
	}
	if len(dataList) == 0 {
		return nil, fmt.Errorf("我们的商品数据为空")
	}

	state.ProductData = dataList

	return state, nil
}

func (w *statisticsOursProduct) generateExcelAndUpload(ctx context.Context, state *StatisticsOursProductContext) (*StatisticsOursProductContext, error) {
	// 1. 获取模板路径
	cwd, _ := pkg.GetModuleDir()
	templatePath := filepath.Join(cwd, "tmpl", "excel_temp", "recharge_statistics_ours_product.xlsx")
	fileName := fmt.Sprintf("statistics_ours_product_%d%d", time.Now().Unix(), rand.Intn(1000))

	// 2. 转换数据为 [][]string
	excelData, totalLoss := w.convertDataToExcelFormat(state.ProductData)

	// 3. 生成 Excel
	req := &excel_generator.ExcelGeneratorRequest{
		TemplatePath: templatePath,
		ExcelData:    excelData,
		StartRow:     3,
		StyleRow:     3,
		Title:        state.Title,
	}
	excelBytes, err := w.toolManager.Common.ExcelGenerator.Call(req)
	if err != nil {
		return nil, fmt.Errorf("生成 Excel 失败: %v", err)
	}

	// 4. Excel 转图片
	picBytes, err := w.toolManager.Common.ImageConverter.Call(fileName+".xlsx", excelBytes, 2)
	if err != nil {
		return nil, fmt.Errorf("Excel 转图片失败: %v", err)
	}

	// 5. 上传 OSS
	url, err := w.ossClient.UploadBytes(fileName+".png", picBytes)
	if err != nil {
		return nil, fmt.Errorf("上传 OSS 失败: %v", err)
	}

	state.ImgUrl = url
	state.ExcelData = excelData
	state.TotalLoss = totalLoss

	return state, nil
}

// convertDataToExcelFormat 将业务数据转换为 Excel 生成器需要的二维字符串数组
func (w *statisticsOursProduct) convertDataToExcelFormat(data []statistics_ours_product.StatisticsOursProductItem) ([][]string, float64) {
	type sortType struct {
		Profit float64
		cells  []string
	}

	var sortList []sortType
	var totalLoss float64
	for _, item := range data {

		var profitVal float64
		// 处理 Profit 字段类型
		switch v := item.Profit.(type) {
		case float64:
			profitVal = v
		case string:
			if val, err := strconv.ParseFloat(v, 64); err == nil {
				profitVal = val
			} else {
				// 解析失败默认为0，或者记录错误日志
				log.Errorf("解析 Profit 字段失败: %v", v)
				profitVal = 0
			}
		default:
			// 其他类型视为0，或者记录错误日志
			log.Errorf("未知 Profit 类型: %T", v)
			profitVal = 0
		}

		// 累加总亏损
		if profitVal < 0 {
			totalLoss += profitVal
		}

		// 过滤利润小于 -100 的记录
		if profitVal > -100 {
			continue
		}

		row := []string{
			item.OursProductName,
			// fmt.Sprintf("%d", item.OursProductId),
			fmt.Sprintf("%v", item.Count),
			// item.TotalPrice,
			// item.SuccessCount,
			fmt.Sprintf("%v", item.SuccessPrice),
			// item.FailCount,
			// item.FailPrice
			fmt.Sprintf("%v", item.Profit),
		}

		sortList = append(sortList, sortType{
			Profit: profitVal,
			cells:  row,
		})
	}

	// 排序
	sort.Slice(sortList, func(i, j int) bool {
		return sortList[i].Profit < sortList[j].Profit
	})

	// 转换为 [][]string
	result := make([][]string, 0, len(sortList))
	for _, item := range sortList {
		result = append(result, item.cells)
	}

	return result, totalLoss
}

func (w *statisticsOursProduct) convertToMap(ctx context.Context, state *StatisticsOursProductContext) (map[string]any, error) {
	return map[string]any{
		"path":  "",
		"url":   state.ImgUrl,
		"data":  state.ExcelData,
		"title": state.Title + fmt.Sprintf("（总亏损 %.2f）", state.TotalLoss),
	}, nil
}
