package localjx

import (
	"encoding/json"
	"fmt"
	"git.rosy.net.cn/baseapi/platformapi/tonglianpayapi"
	"git.rosy.net.cn/baseapi/utils"
	"git.rosy.net.cn/jx-callback/business/jxutils"
	"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/business/partner"
	"git.rosy.net.cn/jx-callback/globals"
	"git.rosy.net.cn/jx-callback/globals/api"
	"strings"
	"time"
)

var (
	TransactionStatus = map[string]string{
		"0000": "交易成功",
		"1001": "交易不存在",
		"2008": "交易处理中,请查询交易,如果是实时交易(例如刷卡支付,交易撤销,退货),建议每隔一段时间(10秒)查询交易",
		"2000": "交易处理中,请查询交易,如果是实时交易(例如刷卡支付,交易撤销,退货),建议每隔一段时间(10秒)查询交易",
		"3888": "流水号重复",
		"3099": "渠道商户错误",
		"3014": "交易金额小于应收手续费",
		"3031": "校验实名信息失败",
		"3088": "交易未支付",
		"3089": "撤销异常,如已影响资金24小时内会做差错退款处理",
		"3050": "交易已被撤销",
		"3999": "1",
		"3889": "1",
		"3045": "1",
	}
)

// BarCodeScannerPay 面对面扫码支付(扫码枪)
func BarCodeScannerPay(vendorOrderId string, userPaymentLabel string) (payCode string, err error) {
	db := dao.GetDB()
	goodsOrder, err := dao.GetSimpleOrder(db, vendorOrderId)
	if err != nil {
		return "", err
	}
	if goodsOrder.VendorID != model.VendorIDJX {
		return "", fmt.Errorf("此订单不是京西订单,无法使用该功能")
	}
	storeDetail, err := dao.GetStoreDetail(db, goodsOrder.JxStoreID, 0, "")
	if err != nil {
		return "", err
	}

	param := &tonglianpayapi.OnlinePayParam{
		Trxamt:      utils.Int64ToStr(goodsOrder.ActualPayPrice),
		Reqsn:       goodsOrder.VendorOrderID,
		Body:        storeDetail.Name,
		Authcode:    userPaymentLabel, // 支付授权码
		Chnlstoreid: utils.Int2Str(goodsOrder.JxStoreID),
		NotifyUrl:   tonglianpayapi.OnlinePayCallbackUrl,
		Signtype:    tonglianpayapi.EncryptionRsa,
	}
	terminfo := &tonglianpayapi.TerminfoBase{
		Termno:     fmt.Sprintf("%d00", goodsOrder.JxStoreID),
		Devicetype: "11",
		Termsn:     fmt.Sprintf("%d00", goodsOrder.JxStoreID),
		Longitude:  fmt.Sprintf("+%s", utils.Float64ToStr(jxutils.IntCoordinate2Standard(storeDetail.Lng))),
		Latitude:   fmt.Sprintf("+%s", utils.Float64ToStr(jxutils.IntCoordinate2Standard(storeDetail.Lat))),
	}
	terminfoBByte, _ := json.Marshal(terminfo)
	param.Terminfo = string(terminfoBByte)

	vendorCode, trxId, remake, err := api.TLpayAPI.CreateOnlineBankOrder(param)
	if err != nil {
		return "", err
	}
	if vendorCode == tonglianpayapi.TrxStatusSuccess {
		goodsOrder.Status = model.OrderStatusFinished
	} else if vendorCode == tonglianpayapi.TrxStatusTransaction || vendorCode == tonglianpayapi.TrxStatusTransaction2 {
		goodsOrder.Status = model.OrderStatusWaitPay
	} else {
		goodsOrder.Status = model.OrderStatusPayFail
	}
	goodsOrder.VendorStatus = vendorCode
	goodsOrder.VendorOrderID2 = trxId
	dao.UpdateEntity(db, goodsOrder, "Status", "VendorStatus", "VendorOrderID2")
	partner.CurOrderManager.OnOrderMsg(goodsOrder, vendorCode, fmt.Sprintf(vendorCode+":"+TransactionStatus[vendorCode]+":%s", remake))
	if vendorCode == "3045" || vendorCode == "3999" || vendorCode == "3889" {
		return remake, nil
	}
	return TransactionStatus[vendorCode], nil
}

// OnTLOnlinePayCallback 通联扫码枪扫码支付回调
func OnTLOnlinePayCallback(call *tonglianpayapi.CallBackResultOnlinePay) (err error) {
	switch call.TrxCode {
	case tonglianpayapi.MsgTypePay, tonglianpayapi.MsgTypePayZFB:
		err = onTLOnlinePayFinished(call)
	case tonglianpayapi.MsgTypeRefund, tonglianpayapi.MsgTypeRefundZFB:
		err = onTLOnlinePayRefund(call)
	default:

	}
	return err
}

func onTLOnlinePayFinished(call *tonglianpayapi.CallBackResultOnlinePay) (err error) {
	db := dao.GetDB()
	if order, err := partner.CurOrderManager.LoadOrder(call.CusorderID, model.VendorIDJX); err == nil {
		if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
			loc, _ := time.LoadLocation("Local")
			t1, _ := time.ParseInLocation("20060102150405", call.PayTime, loc)
			order.OrderFinishedAt = t1
			order.Status = model.OrderStatusFinished
		} else if call.TrxStatus == tonglianpayapi.TrxStatusTransaction || call.TrxStatus == tonglianpayapi.TrxStatusTransaction2 {
			order.Status = model.OrderStatusWaitPay
		} else {
			order.Status = model.OrderStatusPayFail
		}
		order.VendorStatus = call.TrxStatus
		dao.UpdateEntity(db, order, "Status", "OrderFinishedAt", "VendorStatus")
		partner.CurOrderManager.OnOrderMsg(order, call.TrxStatus, fmt.Sprintf(call.TrxStatus+":"+TransactionStatus[call.TrxStatus]+":支付结果回调成功"))

		//if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
		//	err = OnPayFinished(orderPay)
		//}
	} else {
		globals.SugarLogger.Debugf("onTLpayFinished msg:%s, err:%v", utils.Format4Output(call, true), err)
	}
	return err
}

func onTLOnlinePayRefund(call *tonglianpayapi.CallBackResultOnlinePay) (err error) {
	db := dao.GetDB()
	afsOrder, err := partner.CurOrderManager.LoadAfsOrder(call.CusorderID, model.VendorIDJX)
	if err != nil {
		return err
	}
	if afsOrder == nil {
		return fmt.Errorf("CusorderID 错误")
	}
	goodsOrder, err := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, model.VendorIDJX)
	if err != nil {
		return err
	}

	//partner.CurOrderManager.OnOrderMsg(goodsOrder, call.TrxStatus, fmt.Sprintf(call.TrxStatus+":"+TransactionStatus[call.TrxStatus]+":支付结果回调成功"))
	// 退款成功
	if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
		afsOrder.VendorStatus = call.TrxStatus
		afsOrder.Status = model.AfsOrderStatusFinished
		afsOrder.AfsFinishedAt = time.Now()
		dao.UpdateEntity(db, afsOrder, "VendorStatus", "Status", "AfsFinishedAt")
	}

	// 是否全退取消订单
	orderSkuCount := 0
	for _, v := range goodsOrder.Skus {
		orderSkuCount += v.Count
	}

	afsSkus, err := dao.GetStoreAfsOrderSkuList2(db, []string{goodsOrder.VendorOrderID})
	if err != nil {
		return err
	}

	refundSkuCount := 0
	for _, v := range afsSkus {
		refundSkuCount += v.Count
	}

	if orderSkuCount == refundSkuCount {
		goodsOrder.Status = model.OrderStatusCanceled
		goodsOrder.VendorStatus = call.TrxStatus
		dao.UpdateEntity(db, goodsOrder, "Status", "VendorStatus")
	}

	return err
}

// QueryBarCodeScannerStatus 刷新当前订单的支付状态
func QueryBarCodeScannerStatus(vendorOrderId string) (vendorStatus string, err error) {
	db := dao.GetDB()
	goodsOrder, err := dao.GetSimpleOrder(db, vendorOrderId)
	if err != nil {
		return "", err
	}
	if goodsOrder.VendorID != model.VendorIDJX {
		return "", fmt.Errorf("此订单不是京西订单,无法使用该功能")
	}

	param := &tonglianpayapi.PayTransactionStatusQuery{
		Reqsn:     goodsOrder.VendorOrderID,
		Trxid:     "",
		Randomstr: utils.GetUUID(),
		Signtype:  tonglianpayapi.EncryptionRsa,
		Sign:      "",
	}
	vendorCode, remake, err := api.TLpayAPI.QueryPayTransaction(param)
	if err != nil {
		return "", err
	}
	if vendorCode == tonglianpayapi.TrxStatusSuccess {
		goodsOrder.OrderFinishedAt = time.Now()
		goodsOrder.Status = model.OrderStatusFinished
	} else if vendorCode == tonglianpayapi.TrxStatusTransaction || vendorCode == tonglianpayapi.TrxStatusTransaction2 {
		goodsOrder.Status = model.OrderStatusWaitPay
	} else {
		goodsOrder.Status = model.OrderStatusPayFail
	}
	goodsOrder.VendorStatus = vendorCode
	dao.UpdateEntity(db, goodsOrder, "Status", "VendorStatus", "OrderFinishedAt")
	partner.CurOrderManager.OnOrderMsg(goodsOrder, vendorCode, fmt.Sprintf("扫码枪扫码刷新结果:[code:%s,说明:%s,异常原因:%s],本地状态[%d]", vendorCode, TransactionStatus[vendorCode], remake, goodsOrder.Status))

	if vendorCode == "3045" || vendorCode == "3999" || vendorCode == "3889" {
		return remake, nil
	}
	return TransactionStatus[vendorCode], nil
}

// RefundBarCodeScannerOrder 扫码支付订单退单
func RefundBarCodeScannerOrder(ctx *jxcontext.Context, vendorOrderId string, skuIds map[int]int, reason string) (err error) {
	db := dao.GetDB()
	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil || err != nil {
			dao.Rollback(db, txDB)
			if r != nil {
				panic(r)
			}
		}
	}()

	goodsOrder, err := partner.CurOrderManager.LoadOrder(vendorOrderId, model.VendorIDJX)
	if err != nil {
		dao.Rollback(db, txDB)
		return err
	}

	// 检查订单售后
	refundType, refundMoney, err := checkJxAfsOrder(db, goodsOrder, vendorOrderId, skuIds)
	if err != nil {
		dao.Rollback(db, txDB)
		return err
	}

	// 本地添加售后数据
	afsOrder, orderSkuFinancial, afsOrderSkuFinancial, err := addRefundSku(ctx, goodsOrder, skuIds, reason, refundType)
	if err != nil {
		dao.Rollback(db, txDB)
		return err
	}

	// 通知退款,等待回传
	status, errMsg, err := api.TLpayAPI.OrderRefund(&tonglianpayapi.OnLineOrderRefundParam{
		Trxamt:        utils.Int2Str(refundMoney),
		Reqsn:         afsOrder.AfsOrderID,
		Oldreqsn:      goodsOrder.VendorOrderID,
		Oldtrxid:      "",
		Remark:        reason,
		Benefitdetail: "",
		Randomstr:     utils.GetUUID(),
		Signtype:      tonglianpayapi.EncryptionRsa,
		Sign:          "",
	})
	if err != nil {
		return err
	}

	switch status {
	case "0000", "1001", "2008", "2000":
		if err = dao.CreateEntity(db, afsOrder); err != nil {
			dao.Rollback(db, txDB)
			return err
		}
		if err = dao.CreateMultiEntities(db, orderSkuFinancial); err != nil {
			dao.Rollback(db, txDB)
			return err
		}
		if err = dao.CreateMultiEntities(db, afsOrderSkuFinancial); err != nil {
			dao.Rollback(db, txDB)
			return err
		}
		goodsOrder.TotalShopMoney -= int64(refundMoney)
		dao.UpdateEntity(db, goodsOrder, "TotalShopMoney")
		dao.Commit(db, txDB)
	default:
		return fmt.Errorf(errMsg)
	}

	return nil
}

// AddStoreTerm 添加设备终端
func AddStoreTerm(storeId int, operation string) error {
	storeDetail, err := dao.GetStoreDetail(dao.GetDB(), storeId, model.VendorIDJX, "")
	if err != nil {
		return err
	}
	index := strings.LastIndex(storeDetail.Address, storeDetail.DistrictName)
	address := ""
	if index < 0 {
		address = storeDetail.Address
	} else {
		address = storeDetail.Address[index+len(storeDetail.DistrictName):]
	}
	param := &tonglianpayapi.AddTermReq{
		Termno:      fmt.Sprintf("%d00", storeDetail.ID),
		Devicetype:  "11",
		Termsn:      fmt.Sprintf("%d00", storeDetail.ID),
		Operation:   operation,
		Termstate:   "",
		Termaddress: fmt.Sprintf("%s-%s-%s-%s", storeDetail.ProvinceName, storeDetail.CityName, storeDetail.DistrictName, address),
		Signtype:    tonglianpayapi.EncryptionRsa,
		Sign:        "",
	}
	if operation == tonglianpayapi.ScannerOperrationStart {
		param.Termstate = tonglianpayapi.ScannerOperrationStart
	}

	return api.TLpayAPI.TLAddTerm(param)
}

// QueryStoreTerm 查询设备终端状态
func QueryStoreTerm(storeId int) (string, error) {
	storeDetail, err := dao.GetStoreDetail(dao.GetDB(), storeId, model.VendorIDJX, "")
	if err != nil {
		return "", err
	}

	param := &tonglianpayapi.AddTermQuery{
		Termno:   fmt.Sprintf("%d00", storeDetail.ID),
		Signtype: tonglianpayapi.EncryptionRsa,
		Sign:     "",
	}
	return api.TLpayAPI.TLQueryTerm(param)
}

func checkJxAfsOrder(db *dao.DaoDB, goodsOrder *model.GoodsOrder, vendorOrderId string, skuIds map[int]int) (bool, int, error) {
	if goodsOrder.Status != model.OrderStatusFinished {
		return false, 0, fmt.Errorf("订单未完成支付,无法退款(刷新订单状态/联系管理员)")
	}

	// 未结束的售后单,不让继续添加售后单了
	completeAfsOrder, _ := dao.GetAfsOrders(db, model.VendorIDJX, vendorOrderId, "")
	if len(completeAfsOrder) != model.NO {
		for _, v := range completeAfsOrder {
			if v.Status != model.AfsOrderStatusFinished {
				return false, 0, fmt.Errorf("此订单还有未完成的售后单,请稍后再处理")
			}
		}
	}

	totalCount := 0 // 总的商品个数
	skuList := make(map[int]*model.OrderSku, 0)
	for _, v := range goodsOrder.Skus {
		skuList[v.SkuID] = v
		totalCount += v.Count
	}

	// 已经完成商品个数+当次录入商品个数>订单商品个数  不让继续退了
	afsSkuList, _ := dao.GetStoreAfsOrderSkuList2(db, []string{vendorOrderId}) // 已经退款商品
	afsCount := 0                                                              // 总的售后个数
	for _, v := range afsSkuList {
		if v.Count+skuIds[v.SkuID] > skuList[v.SkuID].Count {
			return false, 0, fmt.Errorf("商品[%s],记录购买个数为:%d个,退款个数为:%d个,请检查输入", skuList[v.SkuID].SkuName, skuList[v.SkuID].Count, v.Count+skuIds[v.SkuID])
		}
		afsCount += v.Count + skuIds[v.SkuID]
	}

	if afsCount > totalCount {
		return false, 0, fmt.Errorf("退货商品数计算结果大于订单商品数,请联系管理员")
	}

	totalRefundMoney := 0 // 总退款金额
	for skuId, skuCount := range skuIds {
		if skuList[skuId] != nil && skuList[skuId].Count >= skuCount {
			totalRefundMoney += int(skuList[skuId].SalePrice) * skuCount
		}
	}

	return totalCount == afsCount, totalRefundMoney, nil
}

func addRefundSku(ctx *jxcontext.Context, goodsOrder *model.GoodsOrder, skuIds map[int]int, reason string, refundType bool) (afsOrder *model.AfsOrder, skuFinancial, afsSkuFinancial []*model.OrderSkuFinancial, err error) {
	refundMoney := 0                                                               // 退款金额
	afsOrderID := utils.Int64ToStr(jxutils.GenAfsOrderNo())                        // 退款Id
	orderSkuFinancial := make([]*model.OrderSkuFinancial, 0, len(goodsOrder.Skus)) // 所有商品
	afsOrderSkuFinancial := make([]*model.OrderSkuFinancial, 0, len(skuIds))       // 申请退款商品

	for _, v := range goodsOrder.Skus {
		orderSku := &model.OrderSkuFinancial{
			ModelIDCUL: model.ModelIDCUL{
				CreatedAt:    time.Now(),
				UpdatedAt:    time.Now(),
				LastOperator: ctx.GetUserName(),
			},
			VendorID:          model.VendorIDJX,
			VendorOrderID:     goodsOrder.VendorOrderID,
			VendorSubOrderID:  "",
			AfsOrderID:        "",
			IsAfsOrder:        0,
			VendorStoreID:     utils.Int2Str(goodsOrder.JxStoreID),
			StoreID:           goodsOrder.JxStoreID,
			JxStoreID:         goodsOrder.JxStoreID,
			VendorSkuID:       v.VendorSkuID,
			SkuID:             v.SkuID,
			JxSkuID:           v.JxSkuID,
			PromotionType:     0,
			Name:              v.SkuName,
			ShopPrice:         v.ShopPrice,
			SalePrice:         v.SalePrice,
			Count:             v.Count,
			SkuBoxMoney:       0,
			UserMoney:         v.SalePrice,
			PmSubsidyMoney:    0,
			PmSkuSubsidyMoney: 0,
			PmDeductionsMoney: 0,
			ShopMoney:         v.SalePrice,
			ShopMoneyByCal:    0,
			JxSubsidyMoney:    0,
			JxSkuSubsidyMoney: 0,
			JxDeductionsMoney: 0,
			JxShopMoney:       v.SalePrice,
			RefundMoney:       0,
			RefundMoneyByCal:  0,
			StoreSubID:        0,
			StoreSubName:      "",
		}
		orderSkuFinancial = append(orderSkuFinancial, orderSku)
		if skuIds[v.SkuID] != 0 && v.Count >= skuIds[v.SkuID] {
			refundMoney += int(v.SalePrice) * v.Count
			orderSku.AfsOrderID = afsOrderID
			orderSku.IsAfsOrder = 1
			orderSku.Count = skuIds[v.SkuID]
			orderSku.RefundMoney = v.SalePrice * int64(v.Count)
			afsOrderSkuFinancial = append(afsOrderSkuFinancial, orderSku)
		}
	}

	afsOrder = &model.AfsOrder{
		ModelIDCUL: model.ModelIDCUL{
			CreatedAt:    time.Now(),
			UpdatedAt:    time.Now(),
			LastOperator: ctx.GetUserName(),
		},
		VendorID:          model.VendorIDJX,
		AfsOrderID:        afsOrderID,
		VendorOrderID:     goodsOrder.VendorOrderID,
		VendorStoreID:     utils.Int2Str(goodsOrder.StoreID),
		StoreID:           goodsOrder.StoreID,
		AfsCreatedAt:      time.Now(),
		VendorAppealType:  utils.Int2Str(model.VendorIDJX),
		AppealType:        model.AfsAppealTypeReturnAndRefund,
		VendorReasonType:  "",
		ReasonType:        model.AfsReasonNotOthers,
		ReasonDesc:        utils.LimitUTF8StringLen(reason, 1024),
		ReasonImgList:     "",
		RefundType:        model.AfsTypePartRefund,
		VendorOrgCode:     "0",
		RefundMoney:       int64(refundMoney),
		Status:            model.AfsOrderStatusWait4Approve,
		Flag:              0,
		AfsTotalShopMoney: goodsOrder.ActualPayPrice - int64(refundMoney),
	}
	if refundType {
		afsOrder.RefundType = model.AfsTypeFullRefund
	}

	return afsOrder, orderSkuFinancial, afsOrderSkuFinancial, err
}
