package urlparser

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"regexp"
	"strings"

	"git.lxtend.com/lixiangwuxian/qqbot/constants"
	"git.lxtend.com/lixiangwuxian/qqbot/handler"
	"git.lxtend.com/lixiangwuxian/qqbot/model"
	"git.lxtend.com/lixiangwuxian/qqbot/util"
)

func init() {
	handler.RegisterFrontMatchHandler("[CQ:json", cqJsonUrlParser, constants.LEVEL_USER)
	handler.RegisterFrontMatchHandler("http://", plainTextUrlParser, constants.LEVEL_USER)
	handler.RegisterFrontMatchHandler("https://", plainTextUrlParser, constants.LEVEL_USER)
}

func plainTextUrlParser(msg model.Message) (reply *model.Reply) {
	url := msg.RawMsg
	url = strings.Split(url, " ")[0]
	url = strings.Split(url, "\n")[0]
	url = strings.Split(url, "\r")[0]
	url = strings.Split(url, "\t")[0]
	url, _ = removeTrackingParams(url)
	newUrl, err := resolveFinalURL(url)
	if err != nil {
		return nil
	}
	newUrl, _ = removeTrackingParams(newUrl)
	if util.IsEquivalentURL(url, newUrl) {
		return nil
	}
	return &model.Reply{
		ReplyMsg:       newUrl,
		ReferOriginMsg: true,
		FromMsg:        msg,
	}
}

func cqJsonUrlParser(msg model.Message) (reply *model.Reply) {
	newMsg := strings.ReplaceAll(msg.RawMsg, "\n", "")
	qqdocurl, err := extractQQDocURL(newMsg)
	if err != nil {
		return nil
	}

	return &model.Reply{
		ReplyMsg:       qqdocurl,
		ReferOriginMsg: true,
		FromMsg:        msg,
	}
}

// extractQQDocURL 从字符串中提取 JSON 数据部分
func extractQQDocURL(input string) (string, error) {
	// 使用非贪婪匹配提取 JSON 数据部分
	re := regexp.MustCompile(`\{.*\}`)
	jsonPart := re.FindString(input)
	if jsonPart == "" {
		return "", fmt.Errorf("无法找到 JSON 数据部分")
	}

	// 替换 HTML 实体为普通字符
	jsonPart = strings.ReplaceAll(jsonPart, "&#44;", ",")
	jsonPart = strings.ReplaceAll(jsonPart, "&#91;", "[")
	jsonPart = strings.ReplaceAll(jsonPart, "&#93;", "]")
	jsonPart = strings.ReplaceAll(jsonPart, "&amp;", "&")
	url, err := parseQQDocURL(jsonPart)
	if err != nil {
		return "", fmt.Errorf("解析 JSON 失败: %w", err)
	}
	return url, nil
}

// parseQQDocURL 从 JSON 中提取 qqdocurl 字段
func parseQQDocURL(jsonStr string) (string, error) {
	var jsonData map[string]interface{}

	// 解析 JSON 数据
	if err := json.Unmarshal([]byte(jsonStr), &jsonData); err != nil {
		return "", fmt.Errorf("解析 JSON 失败: %w", err)
	}

	url := ""

	if jsonData["app"] == "com.tencent.miniapp_01" { // 定位到 meta -> detail_1 -> qqdocurl
		meta, ok := jsonData["meta"].(map[string]interface{})
		if !ok {
			return "", fmt.Errorf("找不到 meta 字段")
		}
		detail, ok := meta["detail_1"].(map[string]interface{})
		if !ok {
			return "", fmt.Errorf("找不到 detail_1 字段")
		}
		url, ok = detail["qqdocurl"].(string)
		if !ok {
			return "", fmt.Errorf("找不到 qqdocurl 字段")
		}
		url, _ = resolveFinalURL(url)
		url, _ = removeTrackingParams(url)
	} else if jsonData["app"] == "com.tencent.structmsg" { // 定位到 meta -> news -> jumpUrl
		meta, ok := jsonData["meta"].(map[string]interface{})
		if !ok {
			return "", fmt.Errorf("找不到 meta 字段")
		}
		news, ok := meta["news"].(map[string]interface{})
		if !ok {
			return "", fmt.Errorf("找不到 news 字段")
		}
		url, ok = news["jumpUrl"].(string)
		if !ok {
			return "", fmt.Errorf("找不到 jumpUrl 字段")
		}
	} else if jsonData["app"] == "com.tencent.troopsharecard" { // 定位到 meta -> contact -> jumpUrl
		meta, ok := jsonData["meta"].(map[string]interface{})
		if !ok {
			return "", fmt.Errorf("找不到 meta 字段")
		}
		contact, ok := meta["contact"].(map[string]interface{})
		if !ok {
			return "", fmt.Errorf("找不到 contact 字段")
		}
		url, ok = contact["jumpUrl"].(string)
		if !ok {
			return "", fmt.Errorf("找不到 jumpUrl 字段")
		}
		url, _ = resolveFinalURL(url)
		url, _ = removeTrackingParams(url)
	} else {
		return "", fmt.Errorf("未知的 app 类型")
	}

	return url, nil
}

func removeTrackingParams(rawURL string) (string, error) {
	parsedURL, err := url.Parse(rawURL)
	if err != nil {
		return "", err
	}
	// 仅保留 URL 的 Scheme 和 Host + Path 部分
	return fmt.Sprintf("%s://%s%s", parsedURL.Scheme, parsedURL.Host, parsedURL.Path), nil
}

func resolveFinalURL(initialURL string) (string, error) {
	// 解析 URL 确保其格式正确
	parsedURL, err := url.Parse(initialURL)
	if err != nil {
		return "", fmt.Errorf("URL 解析失败: %w", err)
	}

	// 创建一个 HTTP 客户端
	client := &http.Client{
		// 禁用自动重定向，以便手动处理 302
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastResponse
		},
	}

	// 发起 GET 请求
	resp, err := client.Get(parsedURL.String())
	if err != nil {
		return "", fmt.Errorf("请求失败: %w", err)
	}
	defer resp.Body.Close()

	// 如果是 302 重定向，则递归访问新链接
	if resp.StatusCode == http.StatusFound || resp.StatusCode == http.StatusMovedPermanently {
		redirectURL, err := resp.Location()
		if err != nil {
			return "", fmt.Errorf("解析重定向地址失败: %w", err)
		}
		if redirectURL.String() == initialURL {
			return initialURL, nil
		}
		log.Printf("重定向至: %s\n", redirectURL.String())
		return resolveFinalURL(redirectURL.String())
	}

	// 返回最终的非 302 链接
	return initialURL, nil
}
