package do

import (
	"PaymentCenter/app/constants/common"
	"PaymentCenter/app/constants/errorcode"
	"PaymentCenter/app/models/merchantmodel"
	"PaymentCenter/app/models/paychannelmodel"
	"PaymentCenter/app/services"
	"PaymentCenter/app/third/paymentService/payCommon"
	"PaymentCenter/app/utils"
	"PaymentCenter/config"
	"context"
	"net/url"
	"strconv"
	"xorm.io/builder"

	"PaymentCenter/app/models/ordersmodel"
	"PaymentCenter/app/third/paymentService"
)

type PayParam struct {
	Merchant   *merchantmodel.Merchant
	Channel    *paychannelmodel.PayChannel
	App_id     int64
	OutTradeNo string
	Amount     int
	ExtJson    string
	Desc       string
	ClientIp   string
	ReturnUrl  string
	OpenId     string
}

type Pay struct {
	ctx           *context.Context
	PayParam      *PayParam
	RelationOrder *ordersmodel.Orders
	Order         *ordersmodel.Orders
	PayCode       int
	Url           string
	ThirdMsg      string
}

func NewPayWithPayCheck(paycheck *PayCheck) *Pay {
	return &Pay{
		ctx: paycheck.ctx,
		PayParam: &PayParam{
			Merchant:   paycheck.Merchant,
			Channel:    paycheck.Channel,
			App_id:     paycheck.Reqs.AppId,
			OutTradeNo: paycheck.Reqs.OutTradeNo,
			Amount:     paycheck.Reqs.Amount,
			ExtJson:    paycheck.Reqs.ExtJson,
			Desc:       paycheck.Reqs.Desc,
			ClientIp:   paycheck.AppCheck.Ip,
			ReturnUrl:  paycheck.Reqs.ReturnUrl,
			OpenId:     paycheck.Reqs.OpenId,
		},
		RelationOrder: paycheck.OldOrder,
		PayCode:       errorcode.Success,
	}
}

func (w *Pay) CheckRefundOrder() bool {
	cond := builder.NewCond()
	cond = cond.And(builder.Eq{"app_id": w.PayParam.App_id}, builder.Eq{"order_type": common.ORDER_TYPE_REFUND}, builder.Eq{"out_trade_no": w.PayParam.OutTradeNo})
	order, code := services.OrderFindOne(&ordersmodel.Orders{}, cond)
	if code != errorcode.Success {
		return true
	}
	if order.Status == common.ORDER_STATUS_FAILED {
		return true
	}
	w.Order = order
	return false
}

func (w *Pay) CreateOrder(order_type int) {
	if _, ok := common.OrderTypeList[order_type]; !ok { //判断是否是支持的支付渠道
		w.PayCode = errorcode.PayChannelNotFound
		return
	}

	order := &ordersmodel.Orders{
		MerchantId:   w.PayParam.Merchant.Id,
		PayChannelId: w.PayParam.Channel.Id,
		AppId:        w.PayParam.App_id,
		OutTradeNo:   w.PayParam.OutTradeNo,
		OrderType:    order_type,
		Amount:       w.PayParam.Amount,
		ExtJson:      w.PayParam.ExtJson,
		Desc:         w.PayParam.Desc,
		Status:       common.ORDER_STATUS_WAITPAY,
	}
	if order_type == common.ORDER_TYPE_REFUND {
		order.RefundOrderId = w.RelationOrder.Id
	}
	w.Order, w.PayCode = services.OrderCreate(order)
}

func (w *Pay) PayUrl() (url string) {
	var (
		payFunc func(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error
		ok      bool
		res     paymentService.PayOrderResponse
	)
	thirdPay := &paymentService.PayOrderRequest{
		PayChannelId:  w.PayParam.Channel.Id,
		OrderId:       w.Order.Id,
		ChannelType:   w.PayParam.Channel.ChannelType,
		Description:   w.Order.Desc,
		Amount:        w.Order.Amount,
		PayerClientIp: w.PayParam.ClientIp,
		ReturnUrl:     w.PayParam.ReturnUrl,
		OpenId:        w.PayParam.OpenId,
	}
	// 判断是否是支持的支付渠道,找到对应的配置
	if payFunc, ok = PayWayList[w.PayParam.Channel.ChannelType]; !ok {
		w.PayCode = errorcode.PayChannelNotBuild
		return
	}
	err := payFunc(thirdPay, w.PayParam.Channel)
	if err != nil {
		w.PayCode = errorcode.PayChannelExtJsonError
		return
	}
	switch w.PayParam.Channel.ChannelType {
	// 微信公众号支付,返回的是用户授权链接
	case common.PAY_CHANNEL_WECHAT_JSAPI:
		// 获取授权链接
		res.Result, res.Code = GetWxAuthUrl(w.PayParam.Channel.AppId, w.Order.Id)
	case common.PAY_CHANNEL_ALIPAY_WEB:
		// 支付宝h5
		res = paymentService.PaymentService(*w.ctx, *thirdPay)
	case common.PAY_CHANNEL_WECHAT_H5:
		// 微信h5支付
		res = paymentService.PaymentService(*w.ctx, *thirdPay)
		if res.Result != "" {
			res.Result = config.GetConf().PayService.Host + "/pay/front/api/v1/brokerWechatUrl" + "?url=" + res.Result
		}
	default:
		w.PayCode = errorcode.PayChannelNotBuild
		return
	}

	//res := paymentService.PaymentService(*w.ctx, *thirdPay)

	if res.Code == payCommon.PAY_SUCCESS_CODE {
		w.Order.Status = common.ORDER_STATUS_PAYING
		code := services.OrderUpdate(w.Order, "status")
		if code != errorcode.Success {
			w.PayCode = code
		}
		w.Url = res.Result
	} else {
		w.PayCode = errorcode.PrePayFail
		w.ThirdMsg = res.ErrorMsg
	}

	return
}

func (w *Pay) Refund() {
	var (
		refundFunc func(commonRefundInfo *paymentService.OrderRefundRequest, channel *paychannelmodel.PayChannel) error
		ok         bool
	)
	thirdPayRefund := &paymentService.OrderRefundRequest{
		OrderId:       w.RelationOrder.Id,
		RefundOrderId: w.Order.Id,
		RefundReason:  w.PayParam.Desc,
		RefundAmount:  int64(w.PayParam.Amount),
	}
	if refundFunc, ok = RefundWayList[w.PayParam.Channel.ChannelType]; !ok {
		w.PayCode = errorcode.PayChannelNotBuild
		return
	}
	err := refundFunc(thirdPayRefund, w.PayParam.Channel)
	if err != nil {
		w.PayCode = errorcode.PayChannelExtJsonError
		return
	}
	res := paymentService.OrderRefund(*w.ctx, *thirdPayRefund)
	if res.Code == payCommon.PAY_SUCCESS_CODE {
		w.Order.Status = common.ORDER_STATUS_PAYING
		code := services.OrderUpdate(w.Order, "status")
		if code != errorcode.Success {
			w.PayCode = code
			return
		}
	} else {
		w.PayCode = errorcode.ThirdRefundFail
		w.ThirdMsg = res.ErrorMsg
	}
}

// 关闭订单
func (w *Pay) CloseOrder() {

	var (
		payFunc func(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error
		ok      bool
	)
	thirdPay := &paymentService.PayOrderRequest{
		PayChannelId:  w.PayParam.Channel.Id,
		OrderId:       w.Order.Id,
		ChannelType:   w.PayParam.Channel.ChannelType,
		Description:   w.Order.Desc,
		Amount:        w.Order.Amount,
		PayerClientIp: w.PayParam.ClientIp,
		ReturnUrl:     w.PayParam.ReturnUrl,
	}
	if payFunc, ok = PayWayList[w.PayParam.Channel.ChannelType]; !ok {
		w.PayCode = errorcode.PayChannelNotBuild
		return
	}
	err := payFunc(thirdPay, w.PayParam.Channel)
	if err != nil {
		w.PayCode = errorcode.PayChannelExtJsonError
		return
	}

	closeRequest := paymentService.OrderCloseRequest{
		OrderId:    thirdPay.OrderId,
		PayChannel: utils.PayType(thirdPay.ChannelType),
		Wx:         thirdPay.Wx,
		Ali:        thirdPay.Ali,
	}

	res := paymentService.OrderClose(*w.ctx, closeRequest)
	w.ThirdMsg = res.ErrorMsg
	w.PayCode = res.Code
}

// appid:微信的公众号appid
func GetWxAuthUrl(appid string, orderId int64) (targetUrl string, code int) {
	var (
		// 重定向地址
		redirectUri = config.GetConf().PayService.Host + common.WXCodeRedirectAddress
	)
	baseUrl := "https://open.weixin.qq.com/connect/oauth2/authorize"
	redirectUri = url.QueryEscape(redirectUri)
	responseType := "code"
	scope := "snsapi_base"
	order := strconv.Itoa(int(orderId))

	targetUrl = baseUrl + "?appid=" + appid + "&redirect_uri=" + redirectUri + "&response_type=" + responseType + "&scope=" + scope + "&state=" + order + "#wechat_redirect"
	code = errorcode.Success
	return
}