package logic

import (
	"encoding/json"
	"errors"
	"fusenapi/constants"
	"fusenapi/model/gmodel"
	"fusenapi/utils/auth"
	"fusenapi/utils/basic"
	"time"

	"context"

	"fusenapi/server/pay/internal/svc"
	"fusenapi/server/pay/internal/types"

	"github.com/stripe/stripe-go/v74"
	"github.com/stripe/stripe-go/v74/webhook"
	"github.com/zeromicro/go-zero/core/logx"
	"gorm.io/gorm"
)

type StripeWebhookLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewStripeWebhookLogic(ctx context.Context, svcCtx *svc.ServiceContext) *StripeWebhookLogic {
	return &StripeWebhookLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

// 处理进入前逻辑w,r
// func (l *StripeWebhookLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {

// }

// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *StripeWebhookLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

func (l *StripeWebhookLogic) StripeWebhook(req *types.StripeWebhookReq, userinfo *auth.UserInfo) (resp *basic.Response) {
	// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
	// userinfo 传入值时, 一定不为null

	stripe.Key = l.svcCtx.Config.PayConfig.Stripe.Key
	event := stripe.Event{}

	if err := json.Unmarshal(req.Payload, &event); err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail")
	}

	endpointSecret := l.svcCtx.Config.PayConfig.Stripe.EndpointSecret
	signatureHeader := req.StripeSignature
	event, err := webhook.ConstructEvent(req.Payload, signatureHeader, endpointSecret)
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "Webhook signature verification failed")
	}

	// 新增支付回调事件日志
	var payMethod = int64(constants.PAYMETHOD_STRIPE)
	var nowTime = time.Now().UTC().Unix()
	var eventData = string(event.Data.Raw)
	var fsPayEvent = &gmodel.FsPayEvent{
		PayMethod:    &payMethod,
		EventId:      &event.ID,
		EventType:    &event.Type,
		EventData:    &eventData,
		EventCreated: &event.Created,
		Ip:           &req.RemoteAddr,
		CreatedAt:    &nowTime,
	}
	l.HandlePayEventCreate(fsPayEvent)

	// Unmarshal the event data into an appropriate struct depending on its Type
	switch event.Type {
	case "charge.succeeded":
		// var charge stripe.Charge
		// err := json.Unmarshal(event.Data.Raw, &charge)
		// if err != nil {
		// 	logx.Error(err)
		// 	return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type charge.succeeded")
		// }

	case "checkout.session.completed":
		// checkout checkout.session.completed 处理逻辑
		// var session stripe.CheckoutSession
		// err := json.Unmarshal(event.Data.Raw, &session)
		// if err != nil {
		// 	logx.Error(err)
		// 	return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
		// }
		// fmt.Println("checkout.session.completed")
		// err = l.handlePaymentSessionCompleted(session.ID, session.PaymentIntent.ID)
		// if err != nil {
		// 	return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "checkout.session.completed fail")
		// }
	case "payment_intent.succeeded":
		var paymentIntent stripe.PaymentIntent
		err := json.Unmarshal(event.Data.Raw, &paymentIntent)
		if err != nil {
			logx.Errorf("err:%+v,desc:%s", err, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
			return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
		}
		err = l.HandlePaymentIntentSucceeded(&paymentIntent)
		if err != nil {
			logx.Errorf("err:%+v,desc:%s", err, "pay notify handle payment_intent.succeeded")
			return resp.SetStatusWithMessage(basic.CodePaybackNotOk, "pay notify handle payment_intent.succeeded")
		}
	case "payment_method.attached":
		var paymentMethod stripe.PaymentMethod
		err := json.Unmarshal(event.Data.Raw, &paymentMethod)
		if err != nil {
			logx.Error(err)
			return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_method.attached")
		}
	case "charge.refunded":
		var chargeRefunded stripe.Charge
		err := json.Unmarshal(event.Data.Raw, &chargeRefunded)
		if err != nil {
			logx.Errorf("err:%+v,desc:%s", err, "pay notify Unmarshal fail event.Type charge.refunded")
			return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type charge.refunded")
		}
		err = l.HandleChargeRefunded(&chargeRefunded)
		if err != nil {
			logx.Errorf("err:%+v,desc:%s", err, "pay notify handle charge.refunded")
			return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify handle charge.refunded")
		}

	// ... handle other event types
	default:
		logx.Error("Unhandled event")
		return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type Unhandled")
	}

	return resp.SetStatus(basic.CodeOK)
}

// 回调事件日志
func (l *StripeWebhookLogic) HandlePayEventCreate(fsPayEvent *gmodel.FsPayEvent) error {
	_, err := gmodel.NewFsPayEventModel(l.svcCtx.MysqlConn).CreateOrUpdate(l.ctx, fsPayEvent)
	return err
}

// 退款成功
func (l *StripeWebhookLogic) HandleChargeRefunded(chargeRefunded *stripe.Charge) (err error) {
	// 退款成功
	if chargeRefunded.Status == "succeeded" {
		ctx := l.ctx
		err = l.svcCtx.MysqlConn.Transaction(func(connGorm *gorm.DB) error {
			// 查询支付记录
			payModelT := gmodel.NewFsPayModel(connGorm)
			payModelTRSB := payModelT.BuilderTrans(nil)
			payModelTRSB1 := payModelTRSB.Where("trade_no = ?", chargeRefunded.PaymentIntent.ID).Where("pay_status = ?", constants.PAYSTATUS_SUCCESS).Where("is_refund = ?", 0)
			payInfo, err := payModelT.FindOneByQuery(ctx, payModelTRSB1, nil)
			if err != nil {
				return err
			}
			// 更新支付记录
			*payInfo.IsRefund = 1
			_, err = payModelT.RBCreateOrUpdate(ctx, payInfo)
			if err != nil {
				return err
			}
			// 获取是否还有未退款的数据
			payModelTRSB2 := payModelTRSB.Where("order_number = ?", payInfo.OrderNumber).Where("pay_status = ?", constants.PAYSTATUS_SUCCESS).Where("is_refund = ?", 0)
			count, err := payModelT.FindCount(l.ctx, payModelTRSB2, nil)
			if count == 0 {
				// 退款完成更新订单状态
				orderModelT := gmodel.NewFsOrderModel(connGorm)
				orderModelTRSB := orderModelT.BuilderTrans(nil).Where("sn =?", payInfo.OrderNumber)
				orderInfoRel, err := orderModelT.FindOneByQuery(ctx, orderModelTRSB, nil)
				if err != nil {
					return err
				}
				var isRefunded int64 = 1
				var isRefunding int64 = 1
				var orderStatus int64 = int64(constants.STATUS_NEW_REFUNDED)
				var orderInfo = &gmodel.FsOrder{}
				orderInfo.Id = orderInfoRel.Id
				orderInfo.IsRefunded = &isRefunded
				orderInfo.IsRefunding = &isRefunding
				orderInfo.Status = &orderStatus
				orderModelT.Update(ctx, orderInfo)

				// 记录退款原因
				refundReasonModelT := gmodel.NewFsRefundReasonModel(connGorm)
				refundReasonModelTRSB := refundReasonModelT.BuilderTrans(nil)
				refundReasonModelTRSB1 := refundReasonModelTRSB.Where("order_id =?", orderInfoRel.Id)
				refundReasonInfo, err := refundReasonModelT.FindOneByQuery(ctx, refundReasonModelTRSB1, nil)
				if err != nil {
					return err
				}
				*refundReasonInfo.IsRefund = 1
				_, err = refundReasonModelT.RBCreateOrUpdate(ctx, refundReasonInfo)
				if err != nil {
					return err
				}
			}
			return err
		})
	}
	return err
}

// session完成
// func (l *StripeWebhookLogic) handlePaymentSessionCompleted(sessionId string, tradeNo string) (err error) {
// 	// 查询支付记录
// 	payModel := gmodel.NewFsPayModel(l.svcCtx.MysqlConn)
// 	rsbPay := payModel.RowSelectBuilder(nil)
// 	rsbPay = rsbPay.Where("session_id = ?", sessionId)
// 	payInfo, err := payModel.FindOneByQuery(l.ctx, rsbPay, nil)
// 	if err != nil {
// 		return err
// 	}
// 	if *payInfo.PayStatus == 0 {
// 		*payInfo.TradeNo = tradeNo
// 		_, err = payModel.CreateOrUpdate(l.ctx, payInfo)
// 		if err != nil {
// 			return err
// 		}
// 	} else {
// 		return errors.New("pay status 1")
// 	}
// 	return err
// }

// 付款成功
func (l *StripeWebhookLogic) HandlePaymentIntentSucceeded(paymentIntent *stripe.PaymentIntent) error {
	orderSn, ok := paymentIntent.Metadata["order_sn"]
	if !ok || orderSn == "" {
		return errors.New("order_sn not found")
	}

	// 查询支付记录
	payModel := gmodel.NewFsPayModel(l.svcCtx.MysqlConn)
	rsbPay := payModel.RowSelectBuilder(nil)
	rsbPay = rsbPay.Where("order_number = ?", orderSn).Where("pay_status = ?", constants.PAYSTATUS_UNSUCCESS)
	payInfo, err := payModel.FindOneByQuery(l.ctx, rsbPay, nil)
	if err != nil {
		return err
	}

	//订单信息
	orderDetailTemplateModel := gmodel.NewFsOrderDetailTemplateModel(l.svcCtx.MysqlConn)
	orderModel := gmodel.NewFsOrderModel(l.svcCtx.MysqlConn)
	fsOrderDetailModel := gmodel.NewFsOrderDetailModel(l.svcCtx.MysqlConn)
	fsProductDesignModel := gmodel.NewFsProductDesignModel(l.svcCtx.MysqlConn)

	rsbOrder := orderModel.RowSelectBuilder(nil)
	rsbOrder = rsbOrder.Where("sn =?", orderSn).Preload("FsOrderDetails")
	rsbOrder = rsbOrder.Preload("FsOrderDetails", func(dbPreload *gorm.DB) *gorm.DB {
		return dbPreload.Table(fsOrderDetailModel.TableName()).Preload("FsOrderDetailTemplateInfo", func(dbPreload *gorm.DB) *gorm.DB {
			return dbPreload.Table(orderDetailTemplateModel.TableName()).Preload("FsProductDesignInfo", func(dbPreload *gorm.DB) *gorm.DB {
				return dbPreload.Table(fsProductDesignModel.TableName())
			})
		})
	})
	fsOrderRelInfo, err := orderModel.FindOneByQuery(l.ctx, rsbOrder, nil)
	if err != nil {
		return err
	}

	var designIds []int64
	var cartIds []int64
	if len(fsOrderRelInfo.FsOrderDetails) > 0 {
		for _, fsOrderDetail := range fsOrderRelInfo.FsOrderDetails {
			if fsOrderDetail.FsOrderDetailTemplateInfo.FsProductDesignInfo.Id != 0 {
				designIds = append(designIds, fsOrderDetail.FsOrderDetailTemplateInfo.FsProductDesignInfo.Id)
			}
			cartIds = append(cartIds, *fsOrderDetail.CartId)
		}
	}

	var nowTime int64 = time.Now().UTC().Unix()

	// 支付成功
	if paymentIntent.Status == "succeeded" {
		var card string
		var brand string
		if paymentIntent.LatestCharge.PaymentMethodDetails != nil {
			if paymentIntent.LatestCharge.PaymentMethodDetails.Card != nil {
				if paymentIntent.LatestCharge.PaymentMethodDetails.Card.Last4 != "" {
					card = paymentIntent.LatestCharge.PaymentMethodDetails.Card.Last4
				}
				if paymentIntent.LatestCharge.PaymentMethodDetails.Card.Brand != "" {
					brand = string(paymentIntent.LatestCharge.PaymentMethodDetails.Card.Brand)
				}
			}
		}

		ctx := l.ctx
		err = l.svcCtx.MysqlConn.Transaction(func(connGorm *gorm.DB) error {
			// 更新支付信息
			payModelT := gmodel.NewFsPayModel(connGorm)
			*payInfo.PayStatus = 1
			*payInfo.PayTime = nowTime
			*payInfo.CardNo = card
			*payInfo.Brand = brand
			*payInfo.TradeNo = paymentIntent.ID
			_, err = payModelT.RBCreateOrUpdate(ctx, payInfo)
			if err != nil {
				return err
			}

			// 更新设计数据
			productDesignModelT := gmodel.NewFsProductDesignModel(connGorm)
			productDesignModelTRSB := productDesignModelT.BuilderTrans(ctx, nil)
			var isPay int64 = 1
			err = productDesignModelT.RBUpdateByIds(productDesignModelTRSB, designIds, &gmodel.FsProductDesign{IsPay: &isPay})
			if err != nil {
				return err
			}

			var orderInfo = &gmodel.FsOrder{}
			var orderStatus int64
			var orderIsPartPay int64
			var orderPayedAmount int64
			var orderIsPayCompleted int64
			// 支付记录是首款
			if *payInfo.PayStage == int64(constants.PAYSTAGE_DEPOSIT) {
				orderStatus = int64(constants.STATUS_NEW_PART_PAY)
				orderIsPartPay = 1
				orderInfo.IsPartPay = &orderIsPartPay
				orderPayedAmount = paymentIntent.Amount

				// 删除购物车
				cartModelT := gmodel.NewFsCartModel(connGorm)
				cartModelTRSB := cartModelT.BuilderTrans(ctx, nil)
				err = cartModelT.RBDeleteCartsByIds(cartModelTRSB, cartIds)
				if err != nil {
					return err
				}
			}

			// 支付记录是尾款
			if *payInfo.PayStage == int64(constants.PAYSTAGE_REMAINING) {
				if *fsOrderRelInfo.Status < int64(constants.STATUS_NEW_PAY_COMPLETED) {
					orderStatus = int64(constants.STATUS_NEW_PAY_COMPLETED)
				}
				orderIsPayCompleted = 1
				orderInfo.IsPayCompleted = &orderIsPayCompleted
				orderPayedAmount = *fsOrderRelInfo.PayedAmount + paymentIntent.Amount
			}

			// 更新订单信息
			orderInfo.Id = fsOrderRelInfo.Id
			orderInfo.Status = &orderStatus
			orderInfo.Ptime = &nowTime
			orderInfo.PayedAmount = &orderPayedAmount
			orderModelT := gmodel.NewFsOrderModel(connGorm)
			err = orderModelT.RBUpdate(ctx, orderInfo)
			if err != nil {
				return err
			}
			return err
		})
		if err != nil {
			return err
		}

		//千人千面的处理
		// $renderServer = (new RenderService());
		// $renderServer->thousandsFacesV2($order->id);
		// //清除用户最新的设计
		// $cache = \Yii::$app->cache;
		// $cache->delete(CacheConfigHelper::LAST_DESIGN . $order->user_id);
		// //缓存最新订单编号
		// $cache->set(CacheConfigHelper::USER_ORDERNO . $order->user_id, $order->sn);

		// //查询用户邮箱信息
		// $user = \api\models\User::find()->where(['id' => $order->user_id])->one();
		// $redisData = [
		// 	'key' => 'receipt_download',
		// 	'param' => [
		// 		'email' => $user->email,
		// 		'order_id' => $order->id,
		// 		'pay_id' => $pay->id,
		// 		'type' => 1,//付款成功为1
		// 	]
		// ];
		// Email::timely($redisData);
	}

	// 订单记录
	return nil
}