package report

import (
	"context"
	"encoding/json"
	"fmt"
	html2 "golang.org/x/net/html"
	"hongze/hongze_yb/global"
	"hongze/hongze_yb/utils"
	"net/url"
	"strings"
	"time"
)

// HandleReportContent
// @Description: 处理报告内容（动态图表/表格添加授权token）
// @author: Roc
// @datetime 2025-01-07 10:03:15
// @param body string
// @return newBody string
func HandleReportContent(body string, opType string, tokenMap map[string]string) (newBody string) {
	if body == `` {
		return
	}
	newBody = body

	// 解析HTML
	doc, err := html2.Parse(strings.NewReader(body))
	if err != nil {
		fmt.Println("Error parsing HTML:", err)
		return
	}

	replaceIframeSrc(doc, opType, tokenMap)

	// 输出修改后的HTML
	var modifiedHtml strings.Builder
	err = html2.Render(&modifiedHtml, doc)
	if err != nil {
		fmt.Println("Error rendering HTML:", err)
		return
	}

	newBody = modifiedHtml.String()
	fmt.Println(newBody)

	return
}

// replaceIframeSrc 遍历HTML节点，替换iframe的src属性
func replaceIframeSrc(n *html2.Node, opType string, tokenMap map[string]string) {
	if n.Type == html2.ElementNode && n.Data == "iframe" {
		for i, attr := range n.Attr {
			if attr.Key == "src" {
				newLink := attr.Val
				// 处理链接
				switch opType {
				case `add`:
					newLink = linkAddToken(attr.Val, tokenMap)
				case `del`:
					newLink = linkDelToken(attr.Val)
				}
				// 替换原来的链接
				n.Attr[i].Val = newLink
				break
			}
		}
	}
	// 递归处理子节点
	for c := n.FirstChild; c != nil; c = c.NextSibling {
		replaceIframeSrc(c, opType, tokenMap)
	}
}

// linkAddToken 链接添加token
func linkAddToken(link string, tokenMap map[string]string) string {
	var err error
	defer func() {
		if err != nil {
			global.FILE_LOG.Info("处理链接失败，ERR：" + err.Error())
		}
	}()
	parsedURL, err := url.Parse(link)
	if err != nil {
		return link
	}

	// 获取查询参数
	queryParams := parsedURL.Query()

	// 先移除authToken参数，避免莫名其妙的这个值入库了
	queryParams.Del("authToken")

	// 获取code参数
	code := queryParams.Get("code")
	if code == "" {
		return link
	}

	showType := `chart`
	if strings.Contains(parsedURL.Path, "sheetshow") {
		showType = `excel`
	}

	// 避免报告里面一个图表/表格重复生成token
	key := fmt.Sprint(showType, `:`, code)
	if tokenMap != nil {
		if token, ok := tokenMap[key]; ok {
			// 在链接后面添加一个token值
			return link + "&authToken=" + token
		}
	}

	token, err := GeneralChartToken(showType, code, 30*time.Minute)
	if err != nil {
		return link
	}

	if tokenMap != nil {
		tokenMap[key] = token
	}

	// 在链接后面添加一个token值
	return link + "&authToken=" + token
}

// linkDelToken 链接添加token
func linkDelToken(link string) string {
	var err error
	defer func() {
		if err != nil {
			global.FILE_LOG.Info("处理链接失败，ERR：" + err.Error())
		}
	}()
	parsedURL, err := url.Parse(link)
	if err != nil {
		return link
	}

	// 获取查询参数
	queryParams := parsedURL.Query()

	// 移除authToken参数
	queryParams.Del("authToken")

	// 更新URL的查询参数
	parsedURL.RawQuery = queryParams.Encode()

	return parsedURL.String()
}

// GeneralChartToken
// @Description: 生产图表/表格授权token
// @author: Roc
// @datetime 2025-01-07 10:41:36
// @param showType string
// @param uniqueCode string
// @param expireTime time.Duration
// @return token string
// @return err error
func GeneralChartToken(showType, uniqueCode string, expireTime time.Duration) (token string, err error) {
	// 缓存key
	token = utils.MD5(fmt.Sprint(showType+`:`, uniqueCode, time.Now().UnixNano()/1e6))
	key := fmt.Sprint(utils.CACHE_CHART_AUTH, token)
	err = global.Redis.SetEX(context.TODO(), key, uniqueCode, expireTime).Err()

	return
}

// HandleReportContentStruct
// @Description: 处理内容组件的链接
// @author: Roc
// @datetime 2025-01-07 13:38:39
// @param body string
// @param opType string
// @return newBody string
func HandleReportContentStruct(body string, opType string, tokenMap map[string]string) (newBody string) {
	if body == `` {
		return
	}
	newBody = body

	// 解析JSON数据到map[string]interface{}
	var jsonData []map[string]interface{}
	if err := json.Unmarshal([]byte(body), &jsonData); err != nil {
		fmt.Println("Error parsing JSON:", err)
		return
	}

	// 处理每个组件
	for i := range jsonData {
		if err := processMap(jsonData[i], opType, tokenMap); err != nil {
			fmt.Println("Error processing component:", err)
			return
		}
	}

	// 将处理后的数据转换回JSON字符串
	modifiedJSON, err := json.MarshalIndent(jsonData, "", "  ")
	if err != nil {
		fmt.Println("Error marshaling JSON:", err)
		return
	}
	newBody = string(modifiedJSON)

	return
}

// processMap 递归处理map中的content字段
func processMap(data map[string]interface{}, opType string, tokenMap map[string]string) error {
	for key, value := range data {
		switch v := value.(type) {
		case string:
			if key == "content" {
				contentSource, ok := data["compType"]
				if !ok {
					continue
				}
				contentSourceType, ok := contentSource.(string)
				if !ok {
					continue
				}
				if !utils.InArrayByStr([]string{`sheet`, `chart`}, contentSourceType) {
					continue
				}

				newContent := v
				// 处理链接
				switch opType {
				case `add`:
					newContent = linkAddToken(v, tokenMap)
				case `del`:
					newContent = linkDelToken(v)
				}
				data[key] = newContent
			}
		case map[string]interface{}:
			if err := processMap(v, opType, tokenMap); err != nil {
				return err
			}
		case []interface{}:
			for i := range v {
				if m, ok := v[i].(map[string]interface{}); ok {
					if err := processMap(m, opType, tokenMap); err != nil {
						return err
					}
				}
			}
		}
	}
	return nil
}
