package repoimpl

import (
	"context"
	"errors"
	"gorm.io/gorm"
	"time"
	"unicode/utf8"
	err2 "voucher/api/err"
	"voucher/internal/biz/bo"
	"voucher/internal/biz/repo"
	"voucher/internal/biz/vo"
	"voucher/internal/data"
	"voucher/internal/data/model"
)

// OrderNotifyRepoImpl .
type OrderNotifyRepoImpl struct {
	Base[model.OrderNotify, bo.OrderNotifyBo]
	db *data.Db
}

// NewOrderNotifyRepoImpl .
func NewOrderNotifyRepoImpl(db *data.Db) repo.OrderNotifyRepo {
	return &OrderNotifyRepoImpl{db: db}
}

func (p *OrderNotifyRepoImpl) DB(ctx context.Context) *gorm.DB {
	return p.db.DB(ctx).Model(model.OrderNotify{})
}

func (p *OrderNotifyRepoImpl) GetByID(ctx context.Context, id uint64) (*bo.OrderNotifyBo, error) {
	info := &model.OrderNotify{}

	tx := p.DB(ctx).Where(model.OrderNotify{ID: id}).First(&info)

	if tx.Error != nil {
		if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
			return nil, err2.ErrorDbNotFound("orderNotify数据不存在")
		}
		return nil, tx.Error
	}

	if tx.RowsAffected == 0 {
		return nil, err2.ErrorDbNotFound("订单通知数据不存在")
	}

	return p.ToBo(info), nil
}

func (p *OrderNotifyRepoImpl) GetCountByOrderNoAndEvent(ctx context.Context, orderNo string, event vo.OrderNotifyEvent) (int64, error) {
	var total int64

	tx := p.DB(ctx).Where(model.OrderNotify{OrderNo: orderNo, Event: event.GetValue()}).Count(&total)
	if tx.Error != nil {
		return 0, tx.Error
	}

	return total, nil
}

func (p *OrderNotifyRepoImpl) Create(ctx context.Context, req *bo.OrderNotifyBo) (*bo.OrderNotifyBo, error) {
	now := time.Now()

	info := &model.OrderNotify{
		OrderNo:    req.OrderNo,
		Status:     vo.OrderNotifyStatusWait.GetValue(),
		Request:    req.Request,
		Responses:  "{}",
		NotifyUrl:  req.NotifyUrl,
		Channel:    req.Channel.GetValue(),
		Event:      req.Event.GetValue(),
		Type:       req.Type.GetValue(),
		CreateTime: &now,
		UpdateTime: &now,
	}

	if err := p.DB(ctx).Create(info).Error; err != nil {
		return nil, err
	}

	return p.ToBo(info), nil
}

func (p *OrderNotifyRepoImpl) Success(ctx context.Context, id uint64, responses string) error {
	now := time.Now()

	res := p.DB(ctx).
		Where(model.OrderNotify{
			ID:     id,
			Status: vo.OrderNotifyStatusWait.GetValue(),
		}).
		Updates(model.OrderNotify{
			Status:     vo.OrderNotifyStatusSuccess.GetValue(),
			Responses:  responses,
			UpdateTime: &now,
		})

	if res.Error != nil {
		return res.Error
	}

	return nil
}

func (p *OrderNotifyRepoImpl) Fail(ctx context.Context, id uint64, remark string) error {

	if utf8.RuneCountInString(remark) > 100 {
		runes := []rune(remark)
		if len(runes) > 100 {
			remark = string(runes[:100])
		}
	}

	now := time.Now()

	res := p.DB(ctx).
		Where(model.OrderNotify{
			ID:     id,
			Status: vo.OrderNotifyStatusWait.GetValue(),
		}).
		Updates(model.OrderNotify{
			Status:     vo.OrderNotifyStatusFail.GetValue(),
			Remark:     remark,
			UpdateTime: &now,
		})

	if res.Error != nil {
		return res.Error
	}

	return nil
}
