package cast

import (
	"context"
	"errors"
	"fmt"
	"fonchain-fiee/api/aryshare"
	"fonchain-fiee/api/cast"
	"fonchain-fiee/cmd/config"
	"fonchain-fiee/pkg/model/login"
	"fonchain-fiee/pkg/service"
	"fonchain-fiee/pkg/utils"
	"math/rand"
	"path/filepath"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"go.uber.org/zap"
	"google.golang.org/protobuf/types/known/emptypb"
)

// UpdateCastTag 更新话题标签
func UpdateCastTag(ctx *gin.Context) {
	var req *cast.UpdateCastTagReq
	var err error
	if err = ctx.ShouldBind(&req); err != nil {
		service.Error(ctx, err)
		return
	}
	newCtx := NewCtxWithUserInfo(ctx)
	resp, err := service.CastProvider.UpdateCastTag(newCtx, req)
	if err != nil {
		service.Error(ctx, err)
		return
	}
	service.Success(ctx, resp)
	return
}

// ListCastTags 获取话题标签列表
func ListCastTags(ctx *gin.Context) {
	var req *cast.ListCastTagsReq
	var err error
	if err = ctx.ShouldBind(&req); err != nil {
		service.Error(ctx, err)
		return
	}
	newCtx := NewCtxWithUserInfo(ctx)
	resp, err := service.CastProvider.ListCastTags(newCtx, req)
	if err != nil {
		service.Error(ctx, err)
		return
	}
	service.Success(ctx, resp)
	return
}

// ImportTagBatch 批量导入话题标签
func ImportTagBatch(ctx *gin.Context) {
	// 接收form表单的Excel保存到本地进行解析
	excelFile, err := ctx.FormFile("file")
	if err != nil {
		service.Error(ctx, err)
		return
	}
	tempDir := "./runtime/tag"
	_, err = utils.CheckDirPath(tempDir, true)
	fileName := time.Now().Format("20060102150405") + "_in_tag.xlsx"
	excelPath := filepath.Join(tempDir, fileName)
	if err = ctx.SaveUploadedFile(excelFile, excelPath); err != nil {
		service.Error(ctx, err)
		return
	}
	// 读取Excel中的数据
	excelData, err := excelize.OpenFile(excelPath)
	if err != nil {
		service.Error(ctx, err)
		return
	}
	defer excelData.Close()
	// 解析Excel中的数据
	rows, err := excelData.GetRows("Sheet1")
	if err != nil {
		service.Error(ctx, err)
		return
	}
	req := cast.UpdateCastTagBatchReq{
		Data: make([]*cast.CastTagInfo, 0),
	}
	userInfo := login.GetUserInfoFromC(ctx)
	for line, row := range rows {
		if line == 0 {
			continue
		}
		temp := cast.CastTagInfo{
			CreatorUuid: fmt.Sprint(userInfo.ID),
			CreatorName: userInfo.Name,
			Source:      1, // 固定来源：人工导入
			Status:      1, // 固定状态：有效
		}
		// 解析Excel列：A-话题标签，B-备注
		if len(row) > 0 {
			temp.HashTag = strings.TrimSpace(row[0])
		}
		if len(row) > 1 {
			temp.Remark = strings.TrimSpace(row[1])
		}
		zap.L().Info("ImportTagBatch row", zap.Int("line", line), zap.Strings("row", row))
		// 验证必填字段：话题标签不能为空
		if utils.CleanString(temp.HashTag) == "" {
			temp.Remark = "必填项未填"
			req.Data = append(req.Data, &temp)
			continue
		}
		req.Data = append(req.Data, &temp)
	}
	newCtx := NewCtxWithUserInfo(ctx)
	resp, _err := service.CastProvider.UpdateCastTagBatch(newCtx, &req)
	if _err != nil {
		service.Error(ctx, _err)
		return
	}
	// 打开模板 写入resp 返回的数据
	templatePath := "./data/话题标签导入模板.xlsx"
	template, err := excelize.OpenFile(templatePath)
	if err != nil {
		service.Error(ctx, err)
		return
	}
	defer template.Close()
	var urlResult string
	if resp.FailCount != 0 {
		rowIndex := 2 // 从第2行开始写入（第1行是表头）
		for _, v := range resp.Data {
			if v.Success {
				continue
			}
			// 写入失败的数据到Excel模板（只写入话题标签和备注两列）
			template.SetCellValue("Sheet1", fmt.Sprintf("A%d", rowIndex), v.HashTag)
			template.SetCellValue("Sheet1", fmt.Sprintf("B%d", rowIndex), v.Remark)
			rowIndex++
		}
		resultFilename := strings.Replace(fileName, "_in_tag.xlsx", "_out_tag.xlsx", -1)
		resultPath := fmt.Sprintf("./runtime/tag/%s", resultFilename)
		if err = template.SaveAs(resultPath); err != nil {
			service.Error(ctx, err)
			return
		}
		urlHost := config.AppConfig.System.FieeHost
		urlResult = fmt.Sprintf("%s/api/fiee/static/tag/%s", urlHost, resultFilename)
	}

	service.Success(ctx, map[string]interface{}{
		"successCount": resp.SuccessCount,
		"failCount":    resp.FailCount,
		"resultUrl":    urlResult,
	})
	return
}

// RecalculateCastTagQuoteCount 重新计算话题标签引用数量
func RecalculateCastTagQuoteCount(ctx *gin.Context) {
	newCtx := NewCtxWithUserInfo(ctx)
	// 创建空的请求对象
	req := &emptypb.Empty{}
	resp, err := service.CastProvider.RecalculateCastTagQuoteCount(newCtx, req)
	if err != nil {
		service.Error(ctx, err)
		return
	}
	service.Success(ctx, resp)
	return
}

// findNewTags 对比两次标签，找出新增的标签
func findNewTags(beforeTags, afterTags []string) []string {
	// 将 beforeTags 转换为 map，方便查找
	beforeMap := make(map[string]bool)
	for _, tag := range beforeTags {
		cleanTag := strings.TrimSpace(tag)
		if cleanTag != "" {
			beforeMap[cleanTag] = true
		}
	}

	// 找出 afterTags 中不在 beforeTags 中的标签
	newTags := make([]string, 0)
	for _, tag := range afterTags {
		cleanTag := strings.TrimSpace(tag)
		if cleanTag != "" && !beforeMap[cleanTag] {
			newTags = append(newTags, cleanTag)
		}
	}

	return newTags
}

func GetValidProfileKey(ctx context.Context, platformIDs []uint32) (string, error) {
	if len(platformIDs) == 0 {
		platformIDs = []uint32{1, 2, 3, 5}
	}
	profileKeys, err := service.CastProvider.GetArtistAyrShareInfoByPlatformIDs(ctx, &cast.GetArtistAyrShareInfoByPlatformIDsReq{
		PlatformIDs: platformIDs,
		Page:        1,
		PageSize:    20,
	})
	if err != nil {
		zap.L().Error("GetArtistAyrShareInfoByPlatformIDs failed", zap.Error(err))
		return "", errors.New("获取有效profileKey失败")
	}
	if len(profileKeys.Data) == 0 {
		return "", errors.New("当前没有有效的profileKey")
	}

	// 过滤出所有非空的 profileKey
	validProfileKeys := make([]string, 0)
	for _, item := range profileKeys.Data {
		if item.ProfileKey != "" {
			validProfileKeys = append(validProfileKeys, item.ProfileKey)
		}
	}

	if len(validProfileKeys) == 0 {
		return "", errors.New("profileKey为空")
	}

	// 从有效的 profileKey 中随机选择一个
	randIndex := rand.Intn(len(validProfileKeys))
	return validProfileKeys[randIndex], nil
}

// SaveTagsToDatabase 将标签保存到数据库
func SaveTagsToDatabase(ctx *gin.Context, tags []string, source uint32) error {
	if len(tags) == 0 {
		return nil
	}

	// 获取用户信息
	userInfo := login.GetUserInfoFromC(ctx)
	newCtx := NewCtxWithUserInfo(ctx)

	// 构建批量导入请求
	req := cast.UpdateCastTagBatchReq{
		Data: make([]*cast.CastTagInfo, 0, len(tags)),
	}

	for _, tag := range tags {
		tagInfo := &cast.CastTagInfo{
			HashTag:     tag,
			CreatorUuid: fmt.Sprint(userInfo.ID),
			CreatorName: userInfo.Name,
			Source:      source, // 4: 自动标签（从内容中自动提取）
			Status:      1,      // 1: 有效
		}
		req.Data = append(req.Data, tagInfo)
	}

	// 调用批量导入接口
	_, err := service.CastProvider.UpdateCastTagBatch(newCtx, &req)
	if err != nil {
		err = errors.New("标签保存到数据库失败")
		zap.L().Error("SaveTagsToDatabase UpdateCastTagBatch failed", zap.Error(err))
		return err
	}
	zap.L().Info("SaveTagsToDatabase success", zap.Int("tagCount", len(tags)), zap.Strings("tags", tags), zap.Uint32("source", source))
	return nil
}

func GenerateAutoHashtags(ctx context.Context, post string, max int32, position, language string) (*aryshare.AutoHashtagsResponse, []string, bool, error) {
	// 验证帖子内容
	if post == "" {
		return nil, nil, false, errors.New("帖子内容不能为空")
	}
	// post 的长度不能超过1000个字符
	if len(post) > 1000 {
		return nil, nil, false, errors.New("自动生成标签的帖子内容不能超过1000个字符")
	}

	// 提取生成前的标签
	beforeTags := utils.ExtractTags(post)
	zap.L().Info("GenerateAutoHashtags beforeTags", zap.Strings("beforeTags", beforeTags))

	// 如果标签数量已经达到或超过5个，不需要生成
	if len(beforeTags) >= 5 {
		return nil, nil, false, nil
	}

	// 设置默认值
	if position == "" {
		position = "end"
	}
	if language == "" {
		language = "zh"
	}

	// 如果 max 为0，则根据现有标签数自动计算，确保总数为5
	if max == 0 {
		max = int32(5 - len(beforeTags))
	}

	// 如果此时 max 小于等于0，则直接返回
	if max <= 0 {
		return nil, nil, false, nil
	}

	profileKey, err := GetValidProfileKey(ctx, []uint32{1, 2, 3, 5})
	if err != nil {
		return nil, nil, false, err
	}

	// 构建请求
	req := &aryshare.AutoHashtagsRequest{
		Post:       post,
		Max:        max,
		Position:   position,
		Language:   language,
		ProfileKey: profileKey,
	}

	// 调用 Ayrshare 的 AutoHashtags 接口
	resp, err := service.AyrshareProvider.AutoHashtags(ctx, req)
	if err != nil {
		zap.L().Error("AutoHashtags failed", zap.Error(err))
		return nil, nil, false, errors.New("自动生成标签失败")
	}

	if resp.Post == "" {
		return nil, nil, false, errors.New("自动生成标签返回的帖子内容为空")
	}

	// 去掉自动标签返回的帖子内容多余的引号
	resp.Post = utils.CleanAutoHashtagsQuote(resp.Post)

	// 提取生成后的标签
	afterTags := utils.ExtractTags(resp.Post)
	zap.L().Info("GenerateAutoHashtags afterTags", zap.Strings("afterTags", afterTags))

	// 对比两次标签，找出新增的标签
	newTags := findNewTags(beforeTags, afterTags)

	return resp, newTags, true, nil
}

// AutoHashtags 自动生成标签
func AutoHashtags(ctx *gin.Context) {
	var req *aryshare.AutoHashtagsRequest
	var err error
	if err = ctx.ShouldBind(&req); err != nil {
		service.Error(ctx, err)
		return
	}

	// 调用核心逻辑生成标签
	resp, newTags, needMore, err := GenerateAutoHashtags(
		context.Background(),
		req.Post,
		req.Max,
		req.Position,
		req.Language,
	)
	if err != nil {
		service.Error(ctx, err)
		return
	}

	// 如果标签已满5个，直接返回
	if !needMore {
		service.Success(ctx, map[string]interface{}{
			"message": "当前帖子的标签已经有5个了",
		})
		return
	}

	// 保存新增的标签到数据库，Source 设置为 4（自动标签）
	if len(newTags) > 0 {
		if err = SaveTagsToDatabase(ctx, newTags, 4); err != nil {
			zap.L().Error("SaveTagsToDatabase failed", zap.Error(err), zap.Strings("newTags", newTags))
			err = errors.New("标签保存到数据库失败")
			service.Error(ctx, err)
			return
		}
	}

	service.Success(ctx, resp)
	return
}

// RecommendHashtags 推荐标签
func RecommendHashtags(ctx *gin.Context) {
	var req *aryshare.RecommendHashtagsRequest
	var err error
	if err = ctx.ShouldBind(&req); err != nil {
		service.Error(ctx, err)
		return
	}
	profileKey, err := GetValidProfileKey(context.Background(), []uint32{1})
	if err != nil {
		service.Error(ctx, err)
		return
	}
	req.ProfileKey = profileKey
	resp, err := service.AyrshareProvider.RecommendHashtags(context.Background(), req)
	if err != nil {
		fmt.Println("err", err)
		zap.L().Error("RecommendHashtags failed", zap.Error(err))
		err = errors.New("推荐标签失败")
		service.Error(ctx, err)
		return
	}
	service.Success(ctx, resp)
	return
}

// SearchHashtags 搜索标签
func SearchHashtags(ctx *gin.Context) {
	var req *aryshare.SearchHashtagsRequest
	var err error
	if err = ctx.ShouldBind(&req); err != nil {
		service.Error(ctx, err)
		return
	}
	profileKey, err := GetValidProfileKey(context.Background(), []uint32{3})
	if err != nil {
		service.Error(ctx, err)
		return
	}
	req.ProfileKey = profileKey
	resp, err := service.AyrshareProvider.SearchHashtags(context.Background(), req)
	if err != nil {
		fmt.Println("err", err)
		err = errors.New("获取热门话题标签失败")
		zap.L().Error("SearchHashtags failed", zap.Error(err))
		service.Error(ctx, err)
		return
	}
	service.Success(ctx, resp)
	return
}
