package promo

import (
	"context"

	promomodel "github.com/perfect-panel/server/internal/model/promo"
	subscribeModel "github.com/perfect-panel/server/internal/model/subscribe"
	"github.com/perfect-panel/server/internal/svc"
	"github.com/perfect-panel/server/internal/types"
	"github.com/perfect-panel/server/pkg/logger"
	"github.com/perfect-panel/server/pkg/xerr"
	"github.com/pkg/errors"
)

type SetPriceLogic struct {
	logger.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewSetPriceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SetPriceLogic {
	return &SetPriceLogic{
		Logger: logger.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *SetPriceLogic) SetPrice(req *types.SetPromoPriceRequest) error {
	if _, err := l.svcCtx.PromoModel.FindRule(l.ctx, req.PromoRuleId); err != nil {
		l.Errorw("[SetPromoPrice] Find Rule Error", logger.Field("error", err.Error()))
		return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find promo rule error: %v", err.Error())
	}
	subscribeIds := make([]int64, 0, len(req.Items))
	seenSubscribeIds := make(map[int64]struct{}, len(req.Items))
	for _, item := range req.Items {
		if _, ok := seenSubscribeIds[item.SubscribeId]; ok {
			continue
		}
		seenSubscribeIds[item.SubscribeId] = struct{}{}
		subscribeIds = append(subscribeIds, item.SubscribeId)
	}
	var subscribes []*subscribeModel.Subscribe
	if err := l.svcCtx.DB.WithContext(l.ctx).Model(&subscribeModel.Subscribe{}).Where("id IN ?", subscribeIds).Find(&subscribes).Error; err != nil {
		l.Errorw("[SetPromoPrice] Find Subscribe Error", logger.Field("error", err.Error()))
		return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find subscribe error: %v", err.Error())
	}
	subscribeById := make(map[int64]*subscribeModel.Subscribe, len(subscribes))
	for _, sub := range subscribes {
		subscribeById[sub.Id] = sub
	}
	items := make([]*promomodel.SubscribePromo, 0, len(req.Items))
	cacheKeys := make([]string, 0, len(req.Items))
	for _, item := range req.Items {
		sub, ok := subscribeById[item.SubscribeId]
		if !ok {
			return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "subscribe plan not found")
		}
		originPrice := sub.UnitPrice * item.Quantity
		if item.PromoPrice >= originPrice {
			return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "promo_price must be less than unit_price * quantity")
		}
		items = append(items, &promomodel.SubscribePromo{
			SubscribeId: item.SubscribeId,
			PromoRuleId: req.PromoRuleId,
			Quantity:    item.Quantity,
			PromoPrice:  item.PromoPrice,
		})
		cacheKeys = append(cacheKeys, subscribePromoCacheKey(item.SubscribeId))
	}
	if err := l.svcCtx.PromoModel.UpsertPrices(l.ctx, req.PromoRuleId, items); err != nil {
		l.Errorw("[SetPromoPrice] Database Error", logger.Field("error", err.Error()))
		return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "set promo price error: %v", err.Error())
	}
	if len(cacheKeys) > 0 {
		if err := l.svcCtx.Redis.Del(l.ctx, cacheKeys...).Err(); err != nil {
			l.Errorw("[SetPromoPrice] Delete Cache Error", logger.Field("error", err.Error()))
		}
	}
	return nil
}
