package localjx

import (
	"encoding/json"
	"fmt"
	"git.rosy.net.cn/baseapi/platformapi/lakala"
	"git.rosy.net.cn/jx-callback/business/partner"
	"strings"
	"time"

	"git.rosy.net.cn/jx-callback/globals"

	"git.rosy.net.cn/baseapi/platformapi/tonglianpayapi"
	"git.rosy.net.cn/baseapi/utils"

	"git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin"
	"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
	"git.rosy.net.cn/jx-callback/business/model"
	"git.rosy.net.cn/jx-callback/business/model/dao"
	"git.rosy.net.cn/jx-callback/globals/api"
	"github.com/astaxie/beego/client/orm"
)

func pay4OrderByLaKaLa(ctx *jxcontext.Context, order *model.GoodsOrder, payType int, vendorPayType, subAppID, code, source string) (orderPay *model.OrderPay, err error) {
	var db = dao.GetDB()
	merchantObj, err := dao.GetStoreInfoByMerchantID(db, "", order.JxStoreID, "", "")
	if err != nil {
		return nil, err
	}

	param := &lakala.AggregatePayReq{
		MerchantNo:  merchantObj.MerchantNo2,
		TermNo:      merchantObj.TermNo,
		OutTradeNo:  order.VendorOrderID,
		TotalAmount: utils.Int64ToStr(order.ActualPayPrice),
		LocationInfo: lakala.LocationInfoObj{
			RequestIp: ctx.GetRealRemoteIP(),
		},
		NotifyUrl:     lakala.PayStatusCallback,
		Subject:       fmt.Sprintf("感谢您在本店%s消费,欢迎下次再来", order.StoreName),
		SettleType:    "1",
		AccBusiFields: nil,
	}

	if vendorPayType == tonglianpayapi.PayTypeWxXcx || vendorPayType == "JSAPI" || vendorPayType == tonglianpayapi.PayTypeWxCode {
		accBusiFeilds := &lakala.AccBusiFieldsByWeChat{
			TimeoutExpress: "15",
			SubAppid:       subAppID,
		}
		if source == "pc" || vendorPayType == "JSAPI" {
			accBusiFeilds.DeviceInfo = "WEB"
		}
		switch vendorPayType {
		case "JSAPI":
			param.TransType = "51"
		case tonglianpayapi.PayTypeWxXcx:
			param.TransType = "71"
		}

		authInfo, err := ctx.GetV2AuthInfo()
		// 微信小程序支付
		if err == nil && authInfo.GetAuthType() == weixin.AuthTypeMini && authInfo.GetAuthTypeID() == subAppID {
			accBusiFeilds.UserId = authInfo.GetAuthID()
		}
		if code != "" {
			appAuth := strings.Split(code, "_")
			sessionInfo, err := weixin.GetAPI(appAuth[0]).SNSCode2Session(appAuth[1])
			if err != nil {
				return nil, err
			}
			accBusiFeilds.UserId = sessionInfo.OpenID
		}
		param.AccBusiFields = accBusiFeilds
		param.AccountType = lakala.Wechat
	}

	// 支付宝暂时不关注小程序
	//if vendorPayType == tonglianpayapi.PayTypeZfbJS || vendorPayType == tonglianpayapi.PayTypeZfbApp {
	//	accBusiFeilds := &lakala.AccBusiFieldsByAliPay{
	//		TimeoutExpress: "15",
	//		UserId:         openId,
	//	}
	//	param.AccBusiFields = accBusiFeilds
	//}

	result, err := api.LaKaLaApi.AggregatePay(param)
	if err == nil {
		orderPay = &model.OrderPay{
			PayOrderID:    result.TradeNo,
			PayType:       payType,
			VendorPayType: lakala.PayWayMini,
			TransactionID: result.LogNo,
			VendorOrderID: order.VendorOrderID,
			VendorID:      order.VendorID,
			Status:        0,
			PayCreatedAt:  time.Now(),
			PrepayID:      result.TradeNo,
			CodeURL:       "",
			TotalFee:      int(order.ActualPayPrice),
		}
		if result.AccRespFields != nil {
			fields, _ := json.Marshal(result.AccRespFields)
			orderPay.CodeURL = utils.LimitUTF8StringLen(string(fields), 3200)
		}

		separate := &model.LakalaSeparateAmt{
			MerchantNo:        merchantObj.MerchantNo2,
			VendorOrderID:     order.VendorOrderID,
			StoreId:           order.JxStoreID,
			CmdType:           lakala.SeparateType_SEPATRATE,
			Status:            "1",
			LogNo:             result.LogNo,
			LogDate:           time.Now(),
			OutSeparateNo:     "",
			SeparateNo:        "",
			CalType:           "",
			FinishDate:        "",
			TotalAmt:          "",
			ActualSeparateAmt: "",
			TotalFeeAmt:       "",
			FinalStatus:       "",
			DetailData:        "",
			Remark:            "聚合主扫订单",
		}
		dao.WrapAddIDCULEntity(separate, ctx.GetUserName())
		err = dao.CreateEntity(db, separate)
	}
	order.VendorOrderID2 = result.LogNo
	dao.UpdateEntity(db, order, "VendorOrderID2")

	return orderPay, err
}

func OnLaKaLaPayCallback(call *lakala.PayStatusCallBack) (err error) {
	switch call.TradeStatus {
	case lakala.PayStatusSUCCESS, lakala.PayStatusFAIL: // 支付成功 FAIL-交易失败
		err = onLaKaLaPayFinished(call)
	case lakala.PayStatusCLOSE, lakala.PayStatusREVOKED, lakala.PayStatusREFUND: // CLOSE-订单关闭 REVOKED-订单撤销
		err = onLaKaLaOrderCancel(call)
	case lakala.PayStatusPARTREFUND: // PART_REFUND-部分退款 REFUND-全部退款
		err = onLaKaLaPayRefund(call)
	default:
		//INIT-初始化 CREATE-下单成功  DEAL-交易处理中 UNKNOWN-未知状态
		return nil
	}

	return err
}

// onLaKaLaPayFinished 订单支付成功或失败
func onLaKaLaPayFinished(call *lakala.PayStatusCallBack) (err error) {
	orderPay := &model.OrderPay{
		PayOrderID: call.TradeNo,
	}
	orderPay.DeletedAt = utils.DefaultTimeValue
	db := dao.GetDB()
	if err = dao.GetEntity(db, orderPay, "PayOrderID", "DeletedAt"); err == nil {
		if orderPay.Status != 0 {
			return err
		}
		loc, _ := time.LoadLocation("Local")
		t1, _ := time.ParseInLocation("20060102150405", call.TradeTime, loc)
		orderPay.PayFinishedAt = utils.Time2Pointer(t1)
		orderPay.OriginalData = utils.Format4Output(call, true)
		if call.TradeStatus == lakala.PayStatusSUCCESS {
			orderPay.Status = model.PayStatusYes
		} else {
			orderPay.Status = model.PayStatusFailed
		}
		dao.UpdateEntity(db, orderPay)
		if call.TradeStatus == lakala.PayStatusSUCCESS {
			err = OnPayFinished(orderPay)
		}
	} else {
		globals.SugarLogger.Debugf("onTLpayFinished msg:%s, err:%v", utils.Format4Output(call, true), err)
	}
	return err
}

// onLaKaLaOrderCancel 订单取消或撤单
func onLaKaLaOrderCancel(call *lakala.PayStatusCallBack) (err error) {
	orderPay := &model.OrderPay{
		PayOrderID: call.TradeNo,
	}
	orderPay.DeletedAt = utils.DefaultTimeValue
	db := dao.GetDB()
	if err = dao.GetEntity(db, orderPay, "PayOrderID", "DeletedAt"); err == nil {
		orderPay.Status = model.RefundStatusFailed
		orderPay.PayFinishedAt = utils.Time2Pointer(time.Now())
		dao.UpdateEntity(db, orderPay, "Status", "PayFinishedAt")
		order, _ := partner.CurOrderManager.LoadOrder(orderPay.VendorOrderID, orderPay.VendorID)
		order.Status = model.OrderStatusCanceled
		order.VendorStatus = call.TradeStatus
		order.OrderFinishedAt = time.Now()
		dao.UpdateEntity(db, order, "Status", "VendorStatus", "OrderFinishedAt")
	}
	return err
}

func onLaKaLaPayRefund(call *lakala.PayStatusCallBack) (err error) {
	orderPayRefund := &model.OrderPayRefund{
		RefundID: call.TradeNo,
	}
	db := dao.GetDB()
	if err = dao.GetEntity(db, orderPayRefund, "RefundID"); err != nil && err == orm.ErrNoRows {
		orderPayRefund = &model.OrderPayRefund{
			RefundID:         call.OutTradeNo,
			VendorRefundID:   call.AccTradeNo,
			VendorOrderID:    call.OutTradeNo,
			VendorID:         model.VendorIDJX,
			TransactionID:    call.LogNo,
			Status:           model.RefundStatusYes,
			RefundCreatedAt:  time.Now(),
			RefundFinishedAt: utils.Time2Pointer(time.Now()),
			RefundFee:        utils.Str2Int(call.PayerAmount),
			OriginalData:     "",
		}
		dao.WrapAddIDCULDEntity(orderPayRefund, "system")
		dao.CreateEntity(db, orderPayRefund)
	}

	order, _ := partner.CurOrderManager.LoadOrder(call.OutTradeNo, model.VendorIDJX)
	afsOrder, _ := partner.CurOrderManager.LoadAfsOrder(call.OutTradeNo, model.VendorIDJX)
	if call.TradeStatus == lakala.PayStatusREFUND {
		order.Status = model.OrderStatusCanceled
		orderPayRefund.Status = model.PayStatusRefund
	}
	order.OrderFinishedAt = time.Now()
	order.VendorStatus = call.TradeStatus

	afsOrder.Status = model.AfsOrderStatusFinished
	afsOrder.AfsFinishedAt = time.Now()
	afsOrder.VendorStatus = call.TradeStatus

	orderPayRefund.RefundFinishedAt = utils.Time2Pointer(time.Now())
	dao.UpdateEntity(db, order, "Status", "VendorStatus", "OrderFinishedAt")
	dao.UpdateEntity(db, afsOrder, "Status", "VendorStatus", "AfsFinishedAt")
	dao.UpdateEntity(db, orderPayRefund, "Status", "RefundFinishedAt")
	return err
}
