package wechat

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"sync"
	"time"

	"bindbox-game/internal/pkg/core"
	"bindbox-game/internal/pkg/httpclient"
)

// AccessTokenRequest 获取 access_token 请求参数
type AccessTokenRequest struct {
	AppID     string `json:"appid"`
	AppSecret string `json:"secret"`
	GrantType string `json:"grant_type"`
}

// 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"`
}

// TokenCache access_token 缓存结构
type TokenCache struct {
	Token     string
	ExpiresAt time.Time
	mutex     sync.RWMutex
}

// 全局 token 缓存
var globalTokenCache = &TokenCache{}

// WechatConfig 微信配置
type WechatConfig struct {
	AppID     string
	AppSecret string
}

// QRCodeRequest 获取小程序码请求参数
type QRCodeRequest struct {
	Path       string     `json:"path"`
	Width      int        `json:"width,omitempty"`
	AutoColor  bool       `json:"auto_color,omitempty"`
	LineColor  *LineColor `json:"line_color,omitempty"`
	IsHyaline  bool       `json:"is_hyaline,omitempty"`
	EnvVersion string     `json:"release,omitempty"`
}

type LineColor struct {
	R int `json:"r"`
	G int `json:"g"`
	B int `json:"b"`
}

// QRCodeResponse 获取小程序码响应
type QRCodeResponse struct {
	Buffer  []byte `json:"-"`
	ErrCode int    `json:"errcode,omitempty"`
	ErrMsg  string `json:"errmsg,omitempty"`
}

// QRCodeError 微信API错误响应
type QRCodeError struct {
	ErrCode int    `json:"errcode"`
	ErrMsg  string `json:"errmsg"`
}

func (e *QRCodeError) Error() string {
	return fmt.Sprintf("微信API错误: errcode=%d, errmsg=%s", e.ErrCode, e.ErrMsg)
}

// GetAccessToken 获取微信 access_token
func GetAccessToken(ctx core.Context, config *WechatConfig) (string, error) {
	if config == nil {
		return "", fmt.Errorf("微信配置不能为空")
	}

	if config.AppID == "" {
		return "", fmt.Errorf("AppID 不能为空")
	}

	if config.AppSecret == "" {
		return "", fmt.Errorf("AppSecret 不能为空")
	}
	// 构建请求URL
	url := "https://api.weixin.qq.com/cgi-bin/token"

	// 发送HTTP请求
	client := httpclient.GetHttpClientWithContext(ctx.RequestContext())
	resp, err := client.R().
		SetQueryParams(map[string]string{
			"grant_type": "client_credential",
			"appid":      config.AppID,
			"secret":     config.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为空")
	}

	expiresAt := time.Now().Add(time.Duration(tokenResp.ExpiresIn-300) * time.Second)
	globalTokenCache.Token = tokenResp.AccessToken
	globalTokenCache.ExpiresAt = expiresAt

	return tokenResp.AccessToken, nil
}

// GetAccessTokenWithContext 获取微信 access_token（使用 context.Context）
// 用于后台任务等无 core.Context 的场景
func GetAccessTokenWithContext(ctx context.Context, config *WechatConfig) (string, error) {
	if config == nil {
		return "", fmt.Errorf("微信配置不能为空")
	}
	if config.AppID == "" {
		return "", fmt.Errorf("AppID 不能为空")
	}
	if config.AppSecret == "" {
		return "", fmt.Errorf("AppSecret 不能为空")
	}
	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":      config.AppID,
			"secret":     config.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
}

// GetQRCodeWithConfig 通过微信配置获取小程序码（自动获取access_token）
// config: 微信配置（AppID 和 AppSecret）
// request: 请求参数
// 返回: 成功时返回图片二进制数据，失败时返回错误
func GetQRCodeWithConfig(ctx core.Context, config *WechatConfig, request *QRCodeRequest) (*QRCodeResponse, error) {
	// 自动获取 access_token
	accessToken, err := GetAccessToken(ctx, config)
	if err != nil {
		return nil, fmt.Errorf("获取access_token失败: %v", err)
	}

	return GetQRCode(ctx, accessToken, request)
}

// GetQRCode 获取小程序码
// accessToken: 接口调用凭证
// request: 请求参数
// 返回: 成功时返回图片二进制数据，失败时返回错误
func GetQRCode(ctx core.Context, accessToken string, request *QRCodeRequest) (*QRCodeResponse, error) {
	if accessToken == "" {
		return nil, fmt.Errorf("access_token 不能为空")
	}

	if request == nil {
		return nil, fmt.Errorf("请求参数不能为空")
	}

	if request.Path == "" {
		return nil, fmt.Errorf("path 参数不能为空")
	}

	if len(request.Path) > 1024 {
		return nil, fmt.Errorf("path 参数长度不能超过1024个字符")
	}

	// 设置默认值
	if request.Width == 0 {
		request.Width = 430
	}
	if request.Width < 280 {
		request.Width = 280
	}
	if request.Width > 1280 {
		request.Width = 1280
	}

	url := fmt.Sprintf("https://api.weixin.qq.com/wxa/getwxacode?access_token=%s", accessToken)

	requestBody, err := json.Marshal(request)
	if err != nil {
		return nil, fmt.Errorf("序列化请求参数失败: %v", err)
	}

	client := httpclient.GetHttpClientWithContext(ctx.RequestContext())
	resp, err := client.R().
		SetHeader("Content-Type", "application/json").
		SetBody(requestBody).
		Post(url)

	if err != nil {
		return nil, fmt.Errorf("发送HTTP请求失败: %v", err)
	}

	if resp.StatusCode() != http.StatusOK {
		return nil, fmt.Errorf("HTTP请求失败，状态码: %d", resp.StatusCode())
	}

	responseBody := resp.Body()

	if isJSONResponse(responseBody) {
		var qrError QRCodeError
		if err := json.Unmarshal(responseBody, &qrError); err != nil {
			return nil, fmt.Errorf("解析错误响应失败: %v", err)
		}
		return nil, &qrError
	}

	return &QRCodeResponse{
		Buffer: responseBody,
	}, nil
}

func isJSONResponse(data []byte) bool {
	if len(data) == 0 {
		return false
	}

	trimmed := bytes.TrimSpace(data)
	return len(trimmed) > 0 && trimmed[0] == '{'
}

// GenerateQRCode 最简化的小程序码生成接口
func GenerateQRCode(ctx core.Context, appID, appSecret, path string) ([]byte, error) {

	config := &WechatConfig{
		AppID:     appID,
		AppSecret: appSecret,
	}
	request := &QRCodeRequest{
		Path: path,
	}

	response, err := GetQRCodeWithConfig(ctx, config, request)
	if err != nil {
		return nil, err
	}

	return response.Buffer, nil
}
