package repoimpl

import (
	"context"
	"errors"
	"fmt"
	"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"

	"gorm.io/gorm"
)

// MultiNotifyLogRepoImpl .
type MultiNotifyLogRepoImpl struct {
	Base[model.MultiNotifyLog, bo.MultiNotifyLogBo]
	db *data.Db
}

// NewMultiNotifyLogRepoImpl .
func NewMultiNotifyLogRepoImpl(db *data.Db) repo.MultiNotifyLogRepo {
	return &MultiNotifyLogRepoImpl{db: db}
}

func (p *MultiNotifyLogRepoImpl) DB(ctx context.Context) *gorm.DB {
	return p.db.DB(ctx).WithContext(ctx).Model(model.MultiNotifyLog{})
}

func (p *MultiNotifyLogRepoImpl) Create(ctx context.Context, req *bo.MultiNotifyLogBo) (*bo.MultiNotifyLogBo, error) {

	now := time.Now()

	info := &model.MultiNotifyLog{
		MultiNotifyDataID: req.MultiNotifyDataID,
		OrderNo:           req.OrderNo,
		OutBizNo:          req.OutBizNo,
		CouponID:          req.CouponID,
		ActivityNo:        req.ActivityNo,
		StockID:           req.StockID,
		EventType:         req.EventType,
		Status:            req.Status.GetValue(),
		ConsumeAmount:     req.ConsumeAmount,
		ConsumeTime:       req.ConsumeTime,
		TransactionID:     req.TransactionID,
		OriginReq:         req.OriginReq,
		Request:           req.Request,
		RequestURL:        req.RequestURL,
		RequestStatus:     vo.MultiNotifyLogStatusWait.GetValue(),
		OrderCreateTime:   req.OrderCreateTime,
		CouponCreateTime:  req.CouponCreateTime,
		CreateTime:        &now,
	}

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

	return p.ToBo(info), nil
}

func (p *MultiNotifyLogRepoImpl) GetByID(ctx context.Context, id int64) (*bo.MultiNotifyLogBo, error) {
	var item model.MultiNotifyLog

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

	if tx.Error != nil {
		return nil, fmt.Errorf("b fail %w", tx.Error)
	}

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

	return p.ToBo(&item), nil
}

func (p *MultiNotifyLogRepoImpl) ExistsSuccessByDataIDAndTransactionID(ctx context.Context, multiNotifyDataID int64, transactionID string) (bool, error) {
	var item model.MultiNotifyLog

	err := p.DB(ctx).
		Select("id").
		Where("multi_notify_data_id = ? AND transaction_id = ? AND request_status = ?", multiNotifyDataID, transactionID, vo.MultiNotifyLogStatusSuccess.GetValue()).
		Limit(1).
		Take(&item).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return false, nil
		}
		return false, err
	}

	return true, nil
}

func (p *MultiNotifyLogRepoImpl) Success(ctx context.Context, id int64, response string) error {

	now := time.Now()

	res := p.DB(ctx).
		Where(model.MultiNotifyLog{
			ID:            id,
			RequestStatus: vo.MultiNotifyLogStatusWait.GetValue(),
		}).
		Updates(model.MultiNotifyLog{
			RequestStatus: vo.MultiNotifyLogStatusSuccess.GetValue(),
			Response:      response,
			UpdateTime:    &now,
		})

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

	return nil
}

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

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

	now := time.Now()

	res := p.DB(ctx).
		Where(model.MultiNotifyLog{
			ID:            id,
			RequestStatus: vo.MultiNotifyLogStatusWait.GetValue(),
		}).
		Updates(model.MultiNotifyLog{
			RequestStatus: vo.MultiNotifyLogStatusFail.GetValue(),
			Response:      remark,
			UpdateTime:    &now,
		})

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

	return nil
}
