package wechat

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

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

type orderKey struct {
	OrderNumberType int    `json:"order_number_type"`
	TransactionID   string `json:"transaction_id,omitempty"`
	MchID           string `json:"mchid,omitempty"`
	OutTradeNo      string `json:"out_trade_no,omitempty"`
}

type shippingItem struct {
	TrackingNo     string `json:"tracking_no,omitempty"`
	ExpressCompany string `json:"express_company,omitempty"`
	ItemDesc       string `json:"item_desc"`
}

type payerInfo struct {
	Openid string `json:"openid"`
}

type uploadShippingInfoRequest struct {
	OrderKey       orderKey       `json:"order_key"`
	LogisticsType  int            `json:"logistics_type"`
	DeliveryMode   int            `json:"delivery_mode"`
	IsAllDelivered *bool          `json:"is_all_delivered,omitempty"`
	ShippingList   []shippingItem `json:"shipping_list"`
	UploadTime     string         `json:"upload_time"`
	Payer          *payerInfo     `json:"payer,omitempty"`
}

type commonResp struct {
	ErrCode int    `json:"errcode"`
	ErrMsg  string `json:"errmsg"`
}

func isOrderNotFoundError(err error) bool {
	if err == nil {
		return false
	}
	msg := err.Error()
	if strings.Contains(msg, "errcode=10060001") {
		return true
	}
	if strings.Contains(msg, "支付单不存在") {
		return true
	}
	return false
}

func uploadVirtualShippingInternal(ctx core.Context, accessToken string, key orderKey, payerOpenid string, itemDesc string, uploadTime time.Time) error {
	if accessToken == "" {
		return fmt.Errorf("access_token 不能为空")
	}
	if itemDesc == "" {
		return fmt.Errorf("参数缺失")
	}
	reqBody := &uploadShippingInfoRequest{
		OrderKey:      key,
		LogisticsType: 3,
		DeliveryMode:  1,
		ShippingList:  []shippingItem{{ItemDesc: itemDesc}},
		UploadTime:    uploadTime.Format(time.RFC3339),
	}
	if payerOpenid != "" {
		reqBody.Payer = &payerInfo{Openid: payerOpenid}
	}
	b, _ := json.Marshal(reqBody)
	fmt.Printf("[虚拟发货] 请求 upload_shipping_info order_key=%+v body=%s\n", key, string(b))
	client := httpclient.GetHttpClientWithContext(ctx.RequestContext())
	resp, err := client.R().
		SetQueryParam("access_token", accessToken).
		SetHeader("Content-Type", "application/json").
		SetBody(b).
		Post("https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info")
	if err != nil {
		return err
	}
	var cr commonResp
	if err := json.Unmarshal(resp.Body(), &cr); err != nil {
		return fmt.Errorf("解析响应失败: %v", err)
	}
	if cr.ErrCode != 0 {
		return fmt.Errorf("微信返回错误: errcode=%d, errmsg=%s", cr.ErrCode, cr.ErrMsg)
	}
	return nil
}

func UploadVirtualShippingWithAccessToken(ctx core.Context, accessToken string, transactionID string, payerOpenid string, itemDesc string, uploadTime time.Time) error {
	if transactionID == "" {
		return fmt.Errorf("参数缺失")
	}
	key := orderKey{OrderNumberType: 2, TransactionID: transactionID}
	return uploadVirtualShippingInternal(ctx, accessToken, key, payerOpenid, itemDesc, uploadTime)
}

func UploadVirtualShipping(ctx core.Context, config *WechatConfig, transactionID string, payerOpenid string, itemDesc string, uploadTime time.Time) error {
	accessToken, err := GetAccessToken(ctx, config)
	if err != nil {
		return err
	}
	return UploadVirtualShippingWithAccessToken(ctx, accessToken, transactionID, payerOpenid, itemDesc, uploadTime)
}

func UploadVirtualShippingWithFallback(ctx core.Context, config *WechatConfig, transactionID string, outTradeNo string, payerOpenid string, itemDesc string, uploadTime time.Time) error {
	accessToken, err := GetAccessToken(ctx, config)
	if err != nil {
		return err
	}
	if transactionID != "" {
		err = uploadVirtualShippingInternal(ctx, accessToken, orderKey{OrderNumberType: 2, TransactionID: transactionID}, payerOpenid, itemDesc, uploadTime)
		if err == nil {
			return nil
		}
		if !isOrderNotFoundError(err) {
			return err
		}
		if outTradeNo == "" {
			return err
		}
		fmt.Printf("[虚拟发货] 使用 transaction_id 发货返回支付单不存在，等待重试 transaction_id=%s\n", transactionID)
		time.Sleep(time.Second)
		err = uploadVirtualShippingInternal(ctx, accessToken, orderKey{OrderNumberType: 2, TransactionID: transactionID}, payerOpenid, itemDesc, uploadTime)
		if err == nil {
			return nil
		}
		if !isOrderNotFoundError(err) {
			return err
		}
		fmt.Printf("[虚拟发货] 使用 transaction_id 发货失败，尝试 out_trade_no=%s, 原始错误: %v\n", outTradeNo, err)
	}
	if outTradeNo == "" {
		return fmt.Errorf("transaction_id 和 out_trade_no 均为空")
	}
	mchID := ""
	c := configs.Get()
	if c.WechatPay.MchID != "" {
		mchID = c.WechatPay.MchID
	}
	fmt.Printf("[虚拟发货] fallback 使用 out_trade_no=%s mchid=%s\n", outTradeNo, mchID)
	err = uploadVirtualShippingInternal(ctx, accessToken, orderKey{OrderNumberType: 1, MchID: mchID, OutTradeNo: outTradeNo}, payerOpenid, itemDesc, uploadTime)
	if err == nil {
		return nil
	}
	if !isOrderNotFoundError(err) {
		return err
	}
	fmt.Printf("[虚拟发货] 使用 out_trade_no 发货返回支付单不存在，等待重试 out_trade_no=%s mchid=%s\n", outTradeNo, mchID)
	time.Sleep(time.Second)
	return uploadVirtualShippingInternal(ctx, accessToken, orderKey{OrderNumberType: 1, MchID: mchID, OutTradeNo: outTradeNo}, payerOpenid, itemDesc, uploadTime)
}

func SetMsgJumpPath(ctx core.Context, config *WechatConfig, path string) error {
	if path == "" {
		return fmt.Errorf("path 不能为空")
	}
	accessToken, err := GetAccessToken(ctx, config)
	if err != nil {
		return err
	}
	body := map[string]string{"path": path}
	client := httpclient.GetHttpClientWithContext(ctx.RequestContext())
	resp, err := client.R().
		SetQueryParam("access_token", accessToken).
		SetHeader("Content-Type", "application/json").
		SetBody(body).
		Post("https://api.weixin.qq.com/wxa/sec/order/set_msg_jump_path")
	if err != nil {
		return err
	}
	var cr commonResp
	if err := json.Unmarshal(resp.Body(), &cr); err != nil {
		return fmt.Errorf("解析响应失败: %v", err)
	}
	if cr.ErrCode != 0 {
		return fmt.Errorf("微信返回错误: errcode=%d, errmsg=%s", cr.ErrCode, cr.ErrMsg)
	}
	return nil
}

// UploadVirtualShippingForBackground 后台任务虚拟发货（无 core.Context）
// 用于定时开奖等后台任务场景
func UploadVirtualShippingForBackground(ctx context.Context, config *WechatConfig, transactionID string, outTradeNo string, payerOpenid string, itemDesc string) error {
	accessToken, err := GetAccessTokenWithContext(ctx, config)
	if err != nil {
		return err
	}
	if transactionID != "" {
		key := orderKey{OrderNumberType: 2, TransactionID: transactionID}
		err = uploadVirtualShippingInternalBackground(ctx, accessToken, key, payerOpenid, itemDesc, time.Now())
		if err == nil {
			return nil
		}
		if !isOrderNotFoundError(err) {
			return err
		}
		// 支付单可能尚未同步，等待后重试
		fmt.Printf("[虚拟发货-后台] 使用 transaction_id 发货返回支付单不存在，等待重试 transaction_id=%s\n", transactionID)
		time.Sleep(2 * time.Second)
		err = uploadVirtualShippingInternalBackground(ctx, accessToken, key, payerOpenid, itemDesc, time.Now())
		if err == nil {
			return nil
		}
		if !isOrderNotFoundError(err) {
			return err
		}
		if outTradeNo == "" {
			return err
		}
		fmt.Printf("[虚拟发货-后台] 使用 transaction_id 发货失败，尝试 out_trade_no=%s\n", outTradeNo)
	}
	if outTradeNo == "" {
		return fmt.Errorf("transaction_id 和 out_trade_no 均为空")
	}
	mchID := ""
	c := configs.Get()
	if c.WechatPay.MchID != "" {
		mchID = c.WechatPay.MchID
	}
	fmt.Printf("[虚拟发货-后台] fallback 使用 out_trade_no=%s mchid=%s\n", outTradeNo, mchID)
	err = uploadVirtualShippingInternalBackground(ctx, accessToken, orderKey{OrderNumberType: 1, MchID: mchID, OutTradeNo: outTradeNo}, payerOpenid, itemDesc, time.Now())
	if err == nil {
		return nil
	}
	if !isOrderNotFoundError(err) {
		return err
	}
	// 支付单可能尚未同步，等待后重试
	fmt.Printf("[虚拟发货-后台] 使用 out_trade_no 发货返回支付单不存在，等待重试 out_trade_no=%s mchid=%s\n", outTradeNo, mchID)
	time.Sleep(2 * time.Second)
	return uploadVirtualShippingInternalBackground(ctx, accessToken, orderKey{OrderNumberType: 1, MchID: mchID, OutTradeNo: outTradeNo}, payerOpenid, itemDesc, time.Now())
}

// uploadVirtualShippingInternalBackground 后台虚拟发货内部实现（无 core.Context）
func uploadVirtualShippingInternalBackground(ctx context.Context, accessToken string, key orderKey, payerOpenid string, itemDesc string, uploadTime time.Time) error {
	if accessToken == "" {
		return fmt.Errorf("access_token 不能为空")
	}
	if itemDesc == "" {
		return fmt.Errorf("参数缺失")
	}
	reqBody := &uploadShippingInfoRequest{
		OrderKey:      key,
		LogisticsType: 3,
		DeliveryMode:  1,
		ShippingList:  []shippingItem{{ItemDesc: itemDesc}},
		UploadTime:    uploadTime.Format(time.RFC3339),
	}
	if payerOpenid != "" {
		reqBody.Payer = &payerInfo{Openid: payerOpenid}
	}
	b, _ := json.Marshal(reqBody)
	fmt.Printf("[虚拟发货-后台] 请求 upload_shipping_info order_key=%+v body=%s\n", key, string(b))
	client := httpclient.GetHttpClient()
	resp, err := client.R().
		SetQueryParam("access_token", accessToken).
		SetHeader("Content-Type", "application/json").
		SetBody(b).
		Post("https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info")
	if err != nil {
		return err
	}
	var cr commonResp
	if err := json.Unmarshal(resp.Body(), &cr); err != nil {
		return fmt.Errorf("解析响应失败: %v", err)
	}
	if cr.ErrCode != 0 {
		return fmt.Errorf("微信返回错误: errcode=%d, errmsg=%s", cr.ErrCode, cr.ErrMsg)
	}
	return nil
}
