package do

import (
	"ai_scheduler/internal/config"
	"ai_scheduler/internal/data/impl"
	"ai_scheduler/internal/data/model"
	"ai_scheduler/internal/pkg"
	"ai_scheduler/internal/pkg/lsxd"
	"ai_scheduler/internal/tools/bbxt"
	"ai_scheduler/utils"
	"database/sql"
	"errors"

	"context"
	"encoding/json"
	"fmt"

	"strconv"
	"strings"
	"time"
	"unicode"

	"github.com/gofiber/fiber/v2/log"
	"xorm.io/builder"
)

type Macro struct {
	botGroupImpl         *impl.BotGroupImpl
	botGroupConfigImpl   *impl.BotGroupConfigImpl
	reportDailyCacheImpl *impl.ReportDailyCacheImpl
	config               *config.Config
	rdb                  *utils.Rdb
}

func NewMacro(
	botGroupImpl *impl.BotGroupImpl,
	reportDailyCacheImpl *impl.ReportDailyCacheImpl,
	config *config.Config,
	rdb *utils.Rdb,
	botGroupConfigImpl *impl.BotGroupConfigImpl,
) *Macro {
	return &Macro{
		botGroupImpl:         botGroupImpl,
		reportDailyCacheImpl: reportDailyCacheImpl,
		config:               config,
		rdb:                  rdb,
		botGroupConfigImpl:   botGroupConfigImpl,
	}
}

type MacroFunc func(ctx context.Context, content string, groupConfig *model.AiBotGroupConfig, config *config.Config) (successMsg string, err error, isFinish bool)

func (m *Macro) Router(ctx context.Context, reqContent string, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
	reqContent = strings.TrimSpace(reqContent)
	switch {
	case strings.HasPrefix(reqContent, "[利润同比报表]商品修改"):
		return m.ProductModify(ctx, reqContent, groupConfig)
	case strings.HasPrefix(reqContent, "[利润同比报表]商品列表"):
		return m.ProductList(ctx, groupConfig)
	case strings.HasPrefix(reqContent, "[负利润分析]导出"):
		return m.NegativeProfitGet(ctx)
	case strings.HasPrefix(reqContent, "[负利润分析]更新"):
		return m.NegativeProfitUpdate(ctx, reqContent)
	case strings.HasPrefix(reqContent, "[负利润分析]清理"):
		return m.NegativeProfitClear()
	default:

	}
	return
}

func (m *Macro) NegativeProfitClear() (successMsg string, err error, isFinish bool) {
	dayDate := time.Now().Format(time.DateOnly)
	cond := builder.NewCond()
	cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
	cond = cond.And(builder.Eq{"cache_key": dayDate})
	cond = cond.And(builder.Eq{"status": 1})
	err = m.reportDailyCacheImpl.UpdateByCond(&cond, &model.AiReportDailyCache{
		Status: 2,
	})
	if err != nil {
		err = fmt.Errorf("解析失败:%v", err)
		return
	}
	isFinish = true
	successMsg = "清理成功"
	return
}

func (m *Macro) NegativeProfitUpdate(ctx context.Context, content string) (successMsg string, err error, isFinish bool) {
	//newContent := strings.ReplaceAll(strings.TrimSpace(content), "[负利润分析]更新:", "")
	jsonData, err := ParseLossData(content)
	b, err := bbxt.NewBbxtTools(m.config, lsxd.NewLogin(m.config, m.rdb))
	if err != nil {
		return
	}
	now := time.Now()
	dayData := now.Format(time.DateOnly)
	value, err := b.GetMapResellerLossSumProductRelation(ctx, now, m.GetReportCache)
	if err != nil {
		return
	}
	var setData = make(map[int32]*bbxt.ResellerLossSumProductRelation)
	for k, v := range jsonData {
		if _, ok := value[k]; !ok {
			continue
		}
		for productId, product := range v.Products {
			if _, ok := value[k].Products[productId]; !ok {
				continue
			}
			if value[k].Products[productId].LossReason == product.LossReason {
				continue
			}
			if _, ex := setData[k]; !ex {
				setData[k] = &bbxt.ResellerLossSumProductRelation{
					ResellerName:  value[k].ResellerName,
					AfterSaleName: value[k].AfterSaleName,
					Products:      make(map[int32]*bbxt.LossReason),
				}
			}
			setData[k].Products[productId] = &bbxt.LossReason{
				ProductName: product.ProductName,
				LossReason:  product.LossReason,
			}
		}
	}

	cond := builder.NewCond()
	cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
	cond = cond.And(builder.Eq{"cache_key": dayData})
	cond = cond.And(builder.Eq{"status": 1})
	var cache model.AiReportDailyCache
	err = m.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &cache)
	if err != nil {
		return
	}
	if cache.ID == 0 {

		cache = model.AiReportDailyCache{
			CacheKey:   dayData,
			CacheIndex: bbxt.IndexLossSumDetail,
			Value:      pkg.JsonStringIgonErr(setData),
		}
		_, err = m.reportDailyCacheImpl.Add(&cache)
		if err != nil {
			return
		}
	} else {
		err = m.reportDailyCacheImpl.UpdateByCond(&cond, &model.AiReportDailyCache{
			Value: pkg.JsonStringIgonErr(setData),
		})
		if err != nil {
			return
		}
	}
	isFinish = true
	successMsg = "更新成功"
	return
}

func (m *Macro) NegativeProfitGet(ctx context.Context) (successMsg string, err error, isFinish bool) {
	b, err := bbxt.NewBbxtTools(m.config, lsxd.NewLogin(m.config, m.rdb))
	if err != nil {
		return
	}
	now := time.Now()
	value, err := b.GetMapResellerLossSumProductRelation(ctx, now, m.GetReportCache)
	if err != nil {
		return
	}
	//将value转为string
	//**[供应商id]供应商名称->商务名称**\n
	//└──商品名称：亏损原因\n
	var valueString strings.Builder
	valueString.WriteString("[负利润分析]更新:\n")
	for k, v := range value {
		if len(v.AfterSaleName) == 0 {
			v.AfterSaleName = "未查找到对应商务"
		}
		valueString.WriteString(fmt.Sprintf("**[%d]%s->%s**\n", k, v.ResellerName, v.AfterSaleName))
		for kk, vv := range v.Products {
			valueString.WriteString(fmt.Sprintf("└── [%d]%s:%s\n", kk, vv.ProductName, vv.LossReason))
		}
	}
	successMsg = valueString.String()
	isFinish = true
	return
}

func (m *Macro) ProductModify(ctx context.Context, content string, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
	content = processString(content)
	if parts := strings.SplitN(content, "：", 2); len(parts) == 2 {
		itemInfo := strings.TrimSpace(parts[1])
		log.Infof("商品修改信息: %s", itemInfo)
		groupConfig.ProductName = itemInfo
		cond := builder.NewCond()
		cond = cond.And(builder.Eq{"config_id": groupConfig.ConfigID})
		err = m.botGroupConfigImpl.UpdateByCond(&cond, groupConfig)
		if err != nil {
			err = fmt.Errorf("修改失败:%v", err)
			return
		}
		successMsg = "修改成功"
		isFinish = true
		return
	}
	return
}

func (m *Macro) ProductList(ctx context.Context, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
	if len(groupConfig.ProductName) == 0 {
		successMsg = "暂未设置"
	} else {
		successMsg = groupConfig.ProductName
		isFinish = true
	}
	return
}

func processString(s string) string {
	// 替换中文逗号为英文逗号
	s = strings.ReplaceAll(s, "，", ",")

	return string(clearSpacialFormat(s))
}

func clearSpacialFormat(s string) (result []rune) {
	//过滤控制字符（如 \n, \t, \r 等）
	for _, char := range s {
		// 判断是否是控制字符（ASCII < 32 或 = 127）
		if !unicode.IsControl(char) {
			// 如果需要完全移除 \n 和 \t，可以改成：
			// if !unicode.IsControl(char)
			result = append(result, char)
		}
	}
	return
}

func ParseLossData(input string) (map[int32]*bbxt.ResellerLossSumProductRelation, error) {
	result := make(map[int32]*bbxt.ResellerLossSumProductRelation)

	// 按行分割
	lines := strings.Split(input, "\n")

	// 跳过第一行的标题
	startIdx := 0
	for i, line := range lines {
		if strings.HasPrefix(line, "[") && strings.Contains(line, "]") && strings.Contains(line, "->") {
			startIdx = i
			break
		}
	}

	var currentResellerID int32
	var currentReseller *bbxt.ResellerLossSumProductRelation

	for i := startIdx; i < len(lines); i++ {
		line := strings.TrimSpace(lines[i])
		if line == "" {
			continue
		}

		// 检查是否是供应商行（以 [ 开头）
		if strings.HasPrefix(line, "[") && strings.Contains(line, "]") {
			// 解析供应商行：[25131]兴业银行-营销系统->未查找到对应商务

			// 找到第一个 ] 的位置
			bracketEnd := strings.Index(line, "]")
			if bracketEnd == -1 {
				continue
			}

			// 提取供应商ID
			idStr := line[1:bracketEnd]
			id, err := strconv.ParseInt(idStr, 10, 32)
			if err != nil {
				continue
			}
			currentResellerID = int32(id)

			// 提取供应商名称和商务名称
			remaining := strings.TrimSpace(line[bracketEnd+1:])

			// 分割供应商名称和商务名称
			var resellerName, afterSaleName string
			arrowIdx := strings.Index(remaining, "->")
			if arrowIdx != -1 {
				resellerName = strings.TrimSpace(remaining[:arrowIdx])
				afterSaleName = strings.TrimSpace(remaining[arrowIdx+2:])
			} else {
				resellerName = remaining
				afterSaleName = ""
			}

			// 创建新的供应商对象
			currentReseller = &bbxt.ResellerLossSumProductRelation{
				AfterSaleName: afterSaleName,
				ResellerName:  resellerName,
				Products:      make(map[int32]*bbxt.LossReason),
			}

			result[currentResellerID] = currentReseller

		} else if strings.Contains(line, "└──") {
			// 解析商品行：└── [460]全国话费30元:未填写
			if currentReseller == nil {
				continue
			}

			// 移除└──前缀
			productLine := strings.TrimPrefix(line, "└──")
			productLine = strings.TrimSpace(productLine)

			if !strings.HasPrefix(productLine, "[") {
				continue
			}

			// 找到商品ID的结束位置
			prodBracketEnd := strings.Index(productLine, "]")
			if prodBracketEnd == -1 {
				continue
			}

			// 提取商品ID
			prodIDStr := productLine[1:prodBracketEnd]
			prodID, err := strconv.ParseInt(prodIDStr, 10, 32)
			if err != nil {
				continue
			}

			// 提取商品名称和亏损原因
			prodRemaining := strings.TrimSpace(productLine[prodBracketEnd+1:])

			// 找到冒号分隔符
			colonIdx := strings.Index(prodRemaining, ":")
			var productName, lossReason string

			if colonIdx != -1 {
				productName = strings.TrimSpace(prodRemaining[:colonIdx])
				lossReason = strings.TrimSpace(prodRemaining[colonIdx+1:])
			} else {
				productName = prodRemaining
				lossReason = ""
			}

			// 添加到当前供应商的商品列表中
			currentReseller.Products[int32(prodID)] = &bbxt.LossReason{
				ProductName: productName,
				LossReason:  lossReason,
			}
		}
	}

	return result, nil
}

func (m *Macro) GetReportCache(ctx context.Context, day time.Time, totalDetail []*bbxt.ResellerLoss, bbxtObj *bbxt.BbxtTools) error {
	dayDate := day.Format(time.DateOnly)

	// 1. 从 API 获取数据并填充
	apiRelations, err := bbxtObj.GetResellerLossMannagerAndLossReasonFromApi(ctx, totalDetail)
	if err != nil {
		return fmt.Errorf("get API data failed: %w", err)
	}

	// 使用 API 数据填充损失原因
	fillLossReasonFromData(totalDetail, apiRelations, "未填写")

	// 2. 从缓存获取数据并覆盖
	cachedRelations, err := m.getCachedRelations(dayDate)
	if err != nil {
		return fmt.Errorf("get cache data failed: %w", err)
	}

	// 使用缓存数据覆盖损失原因
	if cachedRelations != nil {
		fillLossReasonFromData(totalDetail, cachedRelations, "")
	}

	return nil
}

// 从缓存获取关系数据
func (m *Macro) getCachedRelations(dayDate string) (map[int32]*bbxt.ResellerLossSumProductRelation, error) {
	cond := builder.NewCond().
		And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail}).
		And(builder.Eq{"cache_key": dayDate}).
		And(builder.Eq{"status": 1})

	var cache model.AiReportDailyCache
	err := m.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &cache)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			// 缓存不存在是正常情况
			return nil, nil
		}
		return nil, fmt.Errorf("query cache failed: %w", err)
	}

	if cache.ID == 0 {
		return nil, nil
	}

	var relations map[int32]*bbxt.ResellerLossSumProductRelation
	if err := json.Unmarshal([]byte(cache.Value), &relations); err != nil {
		return nil, fmt.Errorf("unmarshal cache failed: %w", err)
	}

	return relations, nil
}

// 使用指定数据源填充损失原因
func fillLossReasonFromData(
	totalDetail []*bbxt.ResellerLoss,
	relations map[int32]*bbxt.ResellerLossSumProductRelation,
	defaultReason string, // 当数据不存在时使用的默认值
) {
	for _, detail := range totalDetail {
		resellerRelation, exists := relations[detail.ResellerId]
		if !exists {
			continue
		}

		// 设置售后经理（只有在有值时才设置）
		if resellerRelation.AfterSaleName != "" {
			detail.Manager = resellerRelation.AfterSaleName
		}

		// 为每个产品设置损失原因
		for _, product := range detail.ProductLoss {
			setProductLossReason(product, resellerRelation, defaultReason)
		}
	}
}

// 设置单个产品的损失原因
func setProductLossReason(
	product *bbxt.ProductLoss,
	resellerRelation *bbxt.ResellerLossSumProductRelation,
	defaultReason string,
) {
	// 如果该经销商没有产品数据，跳过
	if resellerRelation.Products == nil {
		return
	}

	productRelation, exists := resellerRelation.Products[product.ProductId]
	if !exists {
		if defaultReason != "" {
			product.LossReason = defaultReason
		}
		return
	}

	// 如果有损失原因则设置，否则使用默认值
	if productRelation.LossReason != "" {
		product.LossReason = productRelation.LossReason
	} else if defaultReason != "" {
		product.LossReason = defaultReason
	}
}
