package service

import (
	"context"
	"fmt"
	"net/http"
	"strconv"
	"time"
	"ycc-server/app/main/api/internal/config"
	"ycc-server/app/main/model"
	"ycc-server/common/ctxdata"
	"ycc-server/pkg/lzkit/lzUtils"

	"github.com/wechatpay-apiv3/wechatpay-go/core"
	"github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers"
	"github.com/wechatpay-apiv3/wechatpay-go/core/downloader"
	"github.com/wechatpay-apiv3/wechatpay-go/core/notify"
	"github.com/wechatpay-apiv3/wechatpay-go/core/option"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments/app"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
	"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
	"github.com/wechatpay-apiv3/wechatpay-go/utils"
	"github.com/zeromicro/go-zero/core/logx"
)

const (
	TradeStateSuccess    = "SUCCESS"    // 支付成功
	TradeStateRefund     = "REFUND"     // 转入退款
	TradeStateNotPay     = "NOTPAY"     // 未支付
	TradeStateClosed     = "CLOSED"     // 已关闭
	TradeStateRevoked    = "REVOKED"    // 已撤销（付款码支付）
	TradeStateUserPaying = "USERPAYING" // 用户支付中（付款码支付）
	TradeStatePayError   = "PAYERROR"   // 支付失败（其他原因，如银行返回失败）
)

// InitType 初始化类型
type InitType string

const (
	InitTypePlatformCert InitType = "platform_cert" // 平台证书初始化
	InitTypeWxPayPubKey  InitType = "wxpay_pubkey"  // 微信支付公钥初始化
)

type WechatPayService struct {
	config        config.Config
	wechatClient  *core.Client
	notifyHandler *notify.Handler
	userAuthModel model.UserAuthModel
}

// NewWechatPayService 创建微信支付服务实例
func NewWechatPayService(c config.Config, userAuthModel model.UserAuthModel, initType InitType) *WechatPayService {
	switch initType {
	case InitTypePlatformCert:
		return newWechatPayServiceWithPlatformCert(c, userAuthModel)
	case InitTypeWxPayPubKey:
		return newWechatPayServiceWithWxPayPubKey(c, userAuthModel)
	default:
		logx.Errorf("不支持的初始化类型: %s", initType)
		panic(fmt.Sprintf("初始化失败，服务停止: %s", initType))
	}
}

// newWechatPayServiceWithPlatformCert 使用平台证书初始化微信支付服务
func newWechatPayServiceWithPlatformCert(c config.Config, userAuthModel model.UserAuthModel) *WechatPayService {
	// 从配置中加载商户信息
	mchID := c.Wxpay.MchID
	mchCertificateSerialNumber := c.Wxpay.MchCertificateSerialNumber
	mchAPIv3Key := c.Wxpay.MchApiv3Key

	// 从文件中加载商户私钥
	mchPrivateKey, err := utils.LoadPrivateKeyWithPath(c.Wxpay.MchPrivateKeyPath)
	if err != nil {
		logx.Errorf("加载商户私钥失败: %v", err)
		panic(fmt.Sprintf("初始化失败，服务停止: %v", err)) // 记录错误并停止程序
	}

	// 使用商户私钥和其他参数初始化微信支付客户端
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
	}
	client, err := core.NewClient(context.Background(), opts...)
	if err != nil {
		logx.Errorf("创建微信支付客户端失败: %v", err)
		panic(fmt.Sprintf("初始化失败，服务停止: %v", err)) // 记录错误并停止程序
	}

	// 在初始化时获取证书访问器并创建 notifyHandler
	certificateVisitor := downloader.MgrInstance().GetCertificateVisitor(mchID)
	notifyHandler, err := notify.NewRSANotifyHandler(mchAPIv3Key, verifiers.NewSHA256WithRSAVerifier(certificateVisitor))
	if err != nil {
		logx.Errorf("获取证书访问器失败: %v", err)
		panic(fmt.Sprintf("初始化失败，服务停止: %v", err))
	}

	logx.Infof("微信支付客户端初始化成功(平台证书方式)")
	return &WechatPayService{
		config:        c,
		wechatClient:  client,
		notifyHandler: notifyHandler,
		userAuthModel: userAuthModel,
	}
}

// newWechatPayServiceWithWxPayPubKey 使用微信支付公钥初始化微信支付服务
func newWechatPayServiceWithWxPayPubKey(c config.Config, userAuthModel model.UserAuthModel) *WechatPayService {
	// 从配置中加载商户信息
	mchID := c.Wxpay.MchID
	mchCertificateSerialNumber := c.Wxpay.MchCertificateSerialNumber
	mchAPIv3Key := c.Wxpay.MchApiv3Key
	mchPrivateKeyPath := c.Wxpay.MchPrivateKeyPath
	mchPublicKeyID := c.Wxpay.MchPublicKeyID
	mchPublicKeyPath := c.Wxpay.MchPublicKeyPath
	// 从文件中加载商户私钥
	mchPrivateKey, err := utils.LoadPrivateKeyWithPath(mchPrivateKeyPath)
	if err != nil {
		logx.Errorf("加载商户私钥失败: %v", err)
		panic(fmt.Sprintf("初始化失败，服务停止: %v", err))
	}

	// 从文件中加载微信支付平台证书
	mchPublicKey, err := utils.LoadPublicKeyWithPath(mchPublicKeyPath)
	if err != nil {
		logx.Errorf("加载微信支付平台证书失败: %v", err)
		panic(fmt.Sprintf("初始化失败，服务停止: %v", err))
	}

	// 使用商户私钥和其他参数初始化微信支付客户端
	opts := []core.ClientOption{
		option.WithWechatPayPublicKeyAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchPublicKeyID, mchPublicKey),
	}
	client, err := core.NewClient(context.Background(), opts...)
	if err != nil {
		logx.Errorf("创建微信支付客户端失败: %v", err)
		panic(fmt.Sprintf("初始化失败，服务停止: %v", err))
	}

	// 初始化 notify.Handler
	certificateVisitor := downloader.MgrInstance().GetCertificateVisitor(mchID)
	notifyHandler := notify.NewNotifyHandler(
		mchAPIv3Key,
		verifiers.NewSHA256WithRSACombinedVerifier(certificateVisitor, mchPublicKeyID, *mchPublicKey))

	logx.Infof("微信支付客户端初始化成功(微信支付公钥方式)")
	return &WechatPayService{
		config:        c,
		wechatClient:  client,
		notifyHandler: notifyHandler,
		userAuthModel: userAuthModel,
	}
}

// CreateWechatAppOrder 创建微信APP支付订单
func (w *WechatPayService) CreateWechatAppOrder(ctx context.Context, amount float64, description string, outTradeNo string) (string, error) {
	totalAmount := lzUtils.ToWechatAmount(amount)

	// 构建支付请求参数
	payRequest := app.PrepayRequest{
		Appid:       core.String(w.config.Wxpay.AppID),
		Mchid:       core.String(w.config.Wxpay.MchID),
		Description: core.String(description),
		OutTradeNo:  core.String(outTradeNo),
		NotifyUrl:   core.String(w.config.Wxpay.NotifyUrl),
		Amount: &app.Amount{
			Total: core.Int64(totalAmount),
		},
	}

	// 初始化 AppApiService
	svc := app.AppApiService{Client: w.wechatClient}

	// 发起预支付请求
	resp, result, err := svc.Prepay(ctx, payRequest)
	if err != nil {
		return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, result.Response.StatusCode)
	}

	// 返回预支付交易会话标识
	return *resp.PrepayId, nil
}

// CreateWechatMiniProgramOrder 创建微信小程序支付订单
func (w *WechatPayService) CreateWechatMiniProgramOrder(ctx context.Context, amount float64, description string, outTradeNo string, openid string) (interface{}, error) {
	totalAmount := lzUtils.ToWechatAmount(amount)

	// 构建支付请求参数
	payRequest := jsapi.PrepayRequest{
		Appid:       core.String(w.config.WechatMini.AppID),
		Mchid:       core.String(w.config.Wxpay.MchID),
		Description: core.String(description),
		OutTradeNo:  core.String(outTradeNo),
		NotifyUrl:   core.String(w.config.Wxpay.NotifyUrl),
		Amount: &jsapi.Amount{
			Total: core.Int64(totalAmount),
		},
		Payer: &jsapi.Payer{
			Openid: core.String(openid), // 用户的 OpenID，通过前端传入
		}}

	// 初始化 AppApiService
	svc := jsapi.JsapiApiService{Client: w.wechatClient}

	// 发起预支付请求
	resp, result, err := svc.PrepayWithRequestPayment(ctx, payRequest)
	if err != nil {
		return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, result.Response.StatusCode)
	}
	// 返回预支付交易会话标识
	return resp, nil
}

// CreateWechatH5Order 创建微信H5支付订单
func (w *WechatPayService) CreateWechatH5Order(ctx context.Context, amount float64, description string, outTradeNo string, openid string) (interface{}, error) {
	totalAmount := lzUtils.ToWechatAmount(amount)

	// 构建支付请求参数
	payRequest := jsapi.PrepayRequest{
		Appid:       core.String(w.config.WechatH5.AppID),
		Mchid:       core.String(w.config.Wxpay.MchID),
		Description: core.String(description),
		OutTradeNo:  core.String(outTradeNo),
		NotifyUrl:   core.String(w.config.Wxpay.NotifyUrl),
		Amount: &jsapi.Amount{
			Total: core.Int64(totalAmount),
		},
		Payer: &jsapi.Payer{
			Openid: core.String(openid), // 用户的 OpenID，通过前端传入
		}}

	// 初始化 AppApiService
	svc := jsapi.JsapiApiService{Client: w.wechatClient}

	// 发起预支付请求
	resp, result, err := svc.PrepayWithRequestPayment(ctx, payRequest)
	logx.Infof("微信h5支付订单：resp: %+v, result: %+v, err: %+v", resp, result, err)
	if err != nil {
		return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, result.Response.StatusCode)
	}
	// 返回预支付交易会话标识
	return resp, nil
}

// CreateWechatOrder 创建微信支付订单（集成 APP、H5、小程序）
func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64, description string, outTradeNo string) (interface{}, error) {
	// 根据 ctx 中的 platform 判断平台
	platform := ctx.Value("platform").(string)

	var prepayData interface{}
	var err error

	switch platform {
	case model.PlatformWxMini:
		userID, getUidErr := ctxdata.GetUidFromCtx(ctx)
		if getUidErr != nil {
			return "", getUidErr
		}
		userAuthModel, findAuthModelErr := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxMiniOpenID)
		if findAuthModelErr != nil {
			return "", findAuthModelErr
		}
		prepayData, err = w.CreateWechatMiniProgramOrder(ctx, amount, description, outTradeNo, userAuthModel.AuthKey)
		if err != nil {
			return "", err
		}
	case model.PlatformWxH5:
		userID, getUidErr := ctxdata.GetUidFromCtx(ctx)
		if getUidErr != nil {
			return "", getUidErr
		}
		userAuthModel, findAuthModelErr := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxh5OpenID)
		if findAuthModelErr != nil {
			return "", findAuthModelErr
		}
		prepayData, err = w.CreateWechatH5Order(ctx, amount, description, outTradeNo, userAuthModel.AuthKey)
		if err != nil {
			return "", err
		}
	case model.PlatformApp:
		// 如果是 APP 平台，调用 APP 支付订单创建
		prepayData, err = w.CreateWechatAppOrder(ctx, amount, description, outTradeNo)
	default:
		return "", fmt.Errorf("不支持的支付平台: %s", platform)
	}

	// 如果创建支付订单失败，返回错误
	if err != nil {
		return "", fmt.Errorf("支付订单创建失败: %v", err)
	}

	// 返回预支付ID
	return prepayData, nil
}

// HandleWechatPayNotification 处理微信支付回调
func (w *WechatPayService) HandleWechatPayNotification(ctx context.Context, req *http.Request) (*payments.Transaction, error) {
	transaction := new(payments.Transaction)
	_, err := w.notifyHandler.ParseNotifyRequest(ctx, req, transaction)
	if err != nil {
		return nil, fmt.Errorf("微信支付通知处理失败: %v", err)
	}
	// 返回交易信息
	return transaction, nil
}

// HandleRefundNotification 处理微信退款回调
func (w *WechatPayService) HandleRefundNotification(ctx context.Context, req *http.Request) (*refunddomestic.Refund, error) {
	refund := new(refunddomestic.Refund)
	_, err := w.notifyHandler.ParseNotifyRequest(ctx, req, refund)
	if err != nil {
		return nil, fmt.Errorf("微信退款回调通知处理失败: %v", err)
	}
	return refund, nil
}

// QueryOrderStatus 主动查询订单状态
func (w *WechatPayService) QueryOrderStatus(ctx context.Context, transactionID string) (*payments.Transaction, error) {
	svc := jsapi.JsapiApiService{Client: w.wechatClient}

	// 调用 QueryOrderById 方法查询订单状态
	resp, result, err := svc.QueryOrderById(ctx, jsapi.QueryOrderByIdRequest{
		TransactionId: core.String(transactionID),
		Mchid:         core.String(w.config.Wxpay.MchID),
	})
	if err != nil {
		return nil, fmt.Errorf("订单查询失败: %v, 状态码: %d", err, result.Response.StatusCode)
	}
	return resp, nil

}

// WeChatRefund 申请微信退款
func (w *WechatPayService) WeChatRefund(ctx context.Context, outTradeNo string, refundAmount float64, totalAmount float64) error {

	// 生成唯一的退款单号
	outRefundNo := fmt.Sprintf("%s-refund", outTradeNo)

	// 初始化退款服务
	svc := refunddomestic.RefundsApiService{Client: w.wechatClient}

	// 创建退款请求
	resp, result, err := svc.Create(ctx, refunddomestic.CreateRequest{
		OutTradeNo:  core.String(outTradeNo),
		OutRefundNo: core.String(outRefundNo),
		NotifyUrl:   core.String(w.config.Wxpay.RefundNotifyUrl),
		Amount: &refunddomestic.AmountReq{
			Currency: core.String("CNY"),
			Refund:   core.Int64(lzUtils.ToWechatAmount(refundAmount)),
			Total:    core.Int64(lzUtils.ToWechatAmount(totalAmount)),
		},
	})
	if err != nil {
		return fmt.Errorf("微信订单申请退款错误: %v", err)
	}
	// 打印退款结果
	logx.Infof("退款申请成功，状态码=%d，退款单号=%s，微信退款单号=%s", result.Response.StatusCode, *resp.OutRefundNo, *resp.RefundId)
	return nil
}

// GenerateOutTradeNo 生成唯一订单号
func (w *WechatPayService) GenerateOutTradeNo() string {
	length := 16
	timestamp := time.Now().UnixNano()
	timeStr := strconv.FormatInt(timestamp, 10)
	randomPart := strconv.Itoa(int(timestamp % 1e6))
	combined := timeStr + randomPart

	if len(combined) >= length {
		return combined[:length]
	}

	for len(combined) < length {
		combined += strconv.Itoa(int(timestamp % 10))
	}

	return combined
}
