package biz

import (
	"context"
	"errors"
	"fmt"
	"gorm.io/gorm"
	errPb "voucher/api/err"
	"voucher/internal/biz/bo"
	"voucher/internal/biz/vo"
	"voucher/internal/pkg/lock"
)

func (v *VoucherBiz) WechatNotifyConsumer(ctx context.Context, tag string, req *bo.WechatVoucherNotifyBo) error {

	c := vo.WechatNotifyConsumeLockKey.BuildCache([]string{tag, req.PlainText.StockID, req.PlainText.CouponID})

	return lock.NewMutex(v.rdb.Rdb, c.TTL).Lock(ctx, c.Key, func(ctx context.Context) error {

		order, err := v.getOrder(ctx, req)
		if err != nil {
			return err
		}

		if req.PlainText.Status.IsSended() {

			return v.available(ctx, order)

		} else if req.PlainText.Status.IsUsed() {

			return v.notifyUsed(ctx, order, req)

		} else if req.PlainText.Status.IsExpired() {

			return v.expired(ctx, order)

		}

		return fmt.Errorf("未知通知类型:%s", req.PlainText.Status.GetText())
	})
}

func (this *VoucherBiz) getOrder(ctx context.Context, req *bo.WechatVoucherNotifyBo) (*bo.OrderBo, error) {

	order, err := this.OrderRepo.GetByVoucherNo(ctx, req.PlainText.StockCreatorMchid, req.PlainText.StockID, req.PlainText.CouponID)

	if err != nil {

		if !errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, err
		}

		order, err = this.OrderRepo.GetByTransactionId(ctx, req.PlainText.StockCreatorMchid, req.PlainText.StockID, req.PlainText.ConsumeInformation.TransactionID)

		if err != nil {

			if errors.Is(err, gorm.ErrRecordNotFound) {

				return nil, fmt.Errorf("微信回调消费,订单不存在,StockCreatorMchid:%s,StockID:%s,CouponID:%s",
					req.PlainText.StockCreatorMchid,
					req.PlainText.StockID,
					req.PlainText.CouponID,
				)
			}

			return nil, err
		}

		return order, nil
	}

	return order, nil
}

func (v *VoucherBiz) notifyUsed(ctx context.Context, order *bo.OrderBo, req *bo.WechatVoucherNotifyBo) error {

	if order.Status.IsUse() {
		// 券状态已是已使用，忽略不处理
		return nil
	}

	if err := v.OrderRepo.NotifyUsed(ctx, order.ID, req.PlainText.ConsumeInformation.TransactionID); err != nil {
		return err
	}

	return v.notify(ctx, order)
}

func (v *VoucherBiz) available(ctx context.Context, order *bo.OrderBo) error {

	if order.Status.IsSuccess() {
		// 券状态已是可使用，忽略不处理
		return nil
	}

	if err := v.OrderRepo.Available(ctx, order.ID); err != nil {
		return err
	}

	return v.notify(ctx, order)
}

func (v *VoucherBiz) expired(ctx context.Context, order *bo.OrderBo) error {

	if order.Status.IsExpired() {
		// 券状态已是已过期，忽略不处理
		return nil
	}

	if err := v.OrderRepo.Expired(ctx, order.ID); err != nil {
		return err
	}

	//return v.notify(ctx, order)
	return nil // 过期不做通知
}

func (v *VoucherBiz) notify(ctx context.Context, order *bo.OrderBo) error {

	return v.cmbNotify(ctx, order.ID)
}

func (v *VoucherBiz) cmbNotify(ctx context.Context, orderId uint64) error {

	order, err := v.OrderRepo.GetByID(ctx, orderId)
	if err != nil {
		return err
	}

	if orderNotify, err := v.Cmb.Notify(ctx, order); err != nil {

		if !errPb.IsNeedRetryNotify(err) {
			return err
		}

		// 第一次通知失败重试入队
		// 状态回调接口失败需要支持重试  重试间隔为1分钟、2分钟、12分钟、60分钟、360分钟
		return v.PushNotifyRetryDelayMQ(ctx, 60, orderNotify.ID)
	}

	return nil
}
