package notify

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"time"

	"bindbox-game/internal/pkg/httpclient"
	pkgutils "bindbox-game/internal/pkg/utils"
)

// WechatNotifyConfig 微信通知配置
type WechatNotifyConfig struct {
	AppID                   string
	AppSecret               string
	LotteryResultTemplateID string
}

// LotteryResultNotificationRequest 开奖结果通知请求结构
type LotteryResultNotificationRequest struct {
	Touser           string                        `json:"touser"`
	TemplateID       string                        `json:"template_id"`
	Page             string                        `json:"page"`
	MiniprogramState string                        `json:"miniprogram_state"`
	Lang             string                        `json:"lang"`
	Data             LotteryResultNotificationData `json:"data"`
}

// LotteryResultNotificationData 开奖结果通知数据字段
// 根据微信订阅消息模板字段定义
// thing1: 活动名称, phrase3: 中奖结果, thing4: 温馨提示
type LotteryResultNotificationData struct {
	Thing1  DataValue `json:"thing1"`  // 活动名称
	Phrase3 DataValue `json:"phrase3"` // 中奖结果
	Thing4  DataValue `json:"thing4"`  // 温馨提示
}

// DataValue 数据值包装
type DataValue struct {
	Value string `json:"value"`
}

// LotteryResultNotificationResponse 发送结果响应
type LotteryResultNotificationResponse struct {
	Errcode int    `json:"errcode"`
	Errmsg  string `json:"errmsg"`
}

// AccessTokenResponse access_token 响应
type AccessTokenResponse struct {
	AccessToken string `json:"access_token"`
	ExpiresIn   int    `json:"expires_in"`
	ErrCode     int    `json:"errcode,omitempty"`
	ErrMsg      string `json:"errmsg,omitempty"`
}

// getAccessToken 获取微信 access_token
func getAccessToken(ctx context.Context, appID, appSecret string) (string, error) {
	url := "https://api.weixin.qq.com/cgi-bin/token"
	client := httpclient.GetHttpClient()
	resp, err := client.R().
		SetQueryParams(map[string]string{
			"grant_type": "client_credential",
			"appid":      appID,
			"secret":     appSecret,
		}).
		Get(url)
	if err != nil {
		return "", fmt.Errorf("获取access_token失败: %v", err)
	}
	if resp.StatusCode() != http.StatusOK {
		return "", fmt.Errorf("HTTP请求失败，状态码: %d", resp.StatusCode())
	}
	var tokenResp AccessTokenResponse
	if err := json.Unmarshal(resp.Body(), &tokenResp); err != nil {
		return "", fmt.Errorf("解析access_token响应失败: %v", err)
	}
	if tokenResp.ErrCode != 0 {
		return "", fmt.Errorf("获取access_token失败: errcode=%d, errmsg=%s", tokenResp.ErrCode, tokenResp.ErrMsg)
	}
	if tokenResp.AccessToken == "" {
		return "", fmt.Errorf("获取到的access_token为空")
	}
	return tokenResp.AccessToken, nil
}

// SendLotteryResultNotification 发送开奖结果订阅消息
// ctx: context
// cfg: 微信通知配置
// openid: 用户 openid
// activityName: 活动名称
// rewardNames: 中奖奖品列表
// orderNo: 订单编号
// drawTime: 开奖时间
func SendLotteryResultNotification(ctx context.Context, cfg *WechatNotifyConfig, openid string, activityName string, rewardNames []string, orderNo string, drawTime time.Time) error {
	if cfg == nil || cfg.LotteryResultTemplateID == "" {
		fmt.Printf("[开奖通知] 模板ID未配置，跳过发送 openid=%s\n", openid)
		return nil
	}
	if openid == "" {
		fmt.Printf("[开奖通知] openid为空，跳过发送\n")
		return nil
	}

	// 获取 access_token
	accessToken, err := getAccessToken(ctx, cfg.AppID, cfg.AppSecret)
	if err != nil {
		fmt.Printf("[开奖通知] 获取access_token失败: %v\n", err)
		return err
	}
	// 活动名称限制长度（thing类型不超过20个字符）
	activityName = pkgutils.TruncateRunes(activityName, 20)

	// 构建中奖结果描述（phrase类型限制5个汉字以内）
	// 由于奖品名称通常较长，phrase3 放不下，改为固定文案 "恭喜中奖"
	// 将奖品名称放入 Thing4 (温馨提示)，限制 20 字符
	resultPhrase := "恭喜中奖"

	rewardsStr := strings.Join(rewardNames, ",")
	warmTips := pkgutils.TruncateRunes(rewardsStr, 20)

	req := &LotteryResultNotificationRequest{
		Touser:           openid,
		TemplateID:       cfg.LotteryResultTemplateID,
		Page:             "pages/mine/index", // 点击跳转到"我的"页面
		MiniprogramState: "formal",           // 正式版
		Lang:             "zh_CN",
		Data: LotteryResultNotificationData{
			Thing1:  DataValue{Value: activityName}, // 活动名称
			Phrase3: DataValue{Value: resultPhrase}, // 中奖结果
			Thing4:  DataValue{Value: warmTips},     // 温馨提示（中奖奖品）
		},
	}

	fmt.Printf("[开奖通知] 尝试发送 openid=%s activity=%s rewards=%v\n", openid, activityName, rewardNames)

	// 发送请求
	url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=%s", accessToken)
	client := httpclient.GetHttpClient()
	resp, err := client.R().
		SetHeader("Content-Type", "application/json").
		SetBody(req).
		Post(url)
	if err != nil {
		fmt.Printf("[开奖通知] 发送失败: %v\n", err)
		return err
	}

	var result LotteryResultNotificationResponse
	if err := json.Unmarshal(resp.Body(), &result); err != nil {
		fmt.Printf("[开奖通知] 解析响应失败: %v\n", err)
		return err
	}

	if result.Errcode != 0 {
		// 常见错误码：
		// 43101: 用户拒绝接受消息
		// 47003: 模板参数不准确
		fmt.Printf("[开奖通知] 发送失败 errcode=%d errmsg=%s\n", result.Errcode, result.Errmsg)
		return fmt.Errorf("发送订阅消息失败: errcode=%d, errmsg=%s", result.Errcode, result.Errmsg)
	}

	fmt.Printf("[开奖通知] ✅ 发送成功 openid=%s\n", openid)
	return nil
}
