package payment

import (
	"context"
	"strings"

	"bsm/full/module/finance/wallet/internal/excode"
	"bsm/full/module/finance/wallet/internal/logic/alipay"
	"bsm/full/module/finance/wallet/internal/logic/basic"
	"bsm/full/module/finance/wallet/internal/logic/wechat"
	"bsm/full/module/finance/wallet/internal/models"
	pb "bsm/full/module/finance/wallet/pb"
	"git.apinb.com/bsm-sdk/core/env"
	"git.apinb.com/bsm-sdk/core/errcode"
	"git.apinb.com/bsm-sdk/core/printer"
	"git.apinb.com/bsm-sdk/core/service"
	"git.apinb.com/bsm-sdk/core/utils"
)

// 支付-电商订单
func ByOrder(ctx context.Context, in *pb.OrderRequest) (reply *pb.PaymentReply, err error) {
	auth, ok := service.ParseMetaCtx(ctx, nil)
	if ok != nil {
		return nil, ok
	}

	if in.OrderNo == "" || in.Desc == "" {
		return nil, errcode.ErrInvalidArgument
	}

	amount, err := models.GetTransPriceByOrderNo(in.OrderNo)
	if err != nil {
		return nil, errcode.ErrNotFound(404, "order")
	}

	var (
		myWallet, wErr = models.GetWalletByPassportIdentity(auth.ID, auth.Identity)
		paymentRecrod  = models.WalletPayment{
			WalletIdentity: myWallet.Identity,
			Type:           2, //1充值，2为订单
			OrderNo:        in.OrderNo,
			PayChannel:     int8(in.PayChannel),
			PayType:        in.PayType,
			Amount:         amount,
		}
	)
	if wErr != nil || myWallet.Identity == "" {
		return nil, errcode.ErrNotFound(404, "wallet")
	}

	paymentRecrod.Identity = utils.UUID()
	paymentRecrod.PassportID = auth.ID
	paymentRecrod.PassportIdentity = auth.Identity

	var payBodyAttach strings.Builder
	payBodyAttach.WriteString(env.Runtime.Workspace)
	payBodyAttach.WriteString(",")
	payBodyAttach.WriteString(paymentRecrod.Identity)

	replyResult := make(map[string]string)
	switch in.PayChannel {
	case 1:
		wechat, err := wechat.NewWechat()
		if err != nil {
			printer.Error(err.Error())
			return nil, excode.ErrWechatInit
		}

		res, err := wechat.GetResponse(payBodyAttach.String(), in.OrderNo, in.Desc, in.OpenId, amount)
		if err != nil {
			printer.Error(err.Error())
			return nil, excode.ErrWechatGetResp
		}

		switch in.PayType {
		case "JSAPI":
			replyResult, err = wechat.JsapiPaySign(res.PrepayId)
			if err != nil {
				printer.Error(err.Error())
				return nil, excode.ErrWechatGetResp
			}
		case "APP":
			replyResult, err = wechat.AppPaySign(res.PrepayId)
			if err != nil {
				printer.Error(err.Error())
				return nil, excode.ErrWechatGetResp
			}
		case "MINI":
			replyResult, err = wechat.MiniPaySign(res.PrepayId)
			if err != nil {
				printer.Error(err.Error())
				return nil, excode.ErrWechatGetResp
			}
		case "NATIVE":
			replyResult, err = wechat.NativePaySign(payBodyAttach.String(), in.OrderNo, in.Desc, "", in.OpenId, amount)
			if err == nil {
				if v, ok := replyResult["code_url"]; ok {
					replyResult["qr_code"] = v
				}
			} else {
				printer.Error(err.Error())
				return nil, excode.ErrWechatGetResp
			}

		default:
			return nil, excode.ErrPayType
		}

		replyResult["prepay_id"] = res.PrepayId

	case 2:
		var result string
		alipay, err := alipay.NewAlipay()
		if err != nil {
			printer.Error(err.Error())
			return nil, excode.ErrAlipayInit
		}
		alipay.SetBody(payBodyAttach.String(), in.OrderNo, amount)
		switch in.PayType {
		case "WAP":
			result, err = alipay.TradeWapPay()
			if err != nil {
				printer.Error(err.Error())
				return nil, excode.ErrAlipayGetResp
			}
		case "APP":
			result, err = alipay.TradeAppPay()
			if err != nil {
				printer.Error(err.Error())
				return nil, excode.ErrAlipayGetResp
			}
		default:
			return nil, excode.ErrPayType
		}

		replyResult["payUrl"] = result

	case 3:
		walletSrv, err := basic.NewWallet(auth.Identity, in.Password, amount)
		if err != nil {
			return nil, errcode.ErrDB
		}
		err = walletSrv.TradeConsum(amount)
		if err != nil {
			return nil, excode.ErrBalanceNotEnough
		}
	default:
		return nil, excode.ErrPayChannel
	}

	// 写入支付记录表（不可忽略错误）
	if err := models.CreatePaymentRecord(&paymentRecrod); err != nil {
		printer.Error("CreatePaymentRecord failed: ", err.Error())
		return nil, errcode.ErrDB
	}

	//return
	return &pb.PaymentReply{
		Code:   200,
		Result: replyResult,
	}, nil
}
