package promo

import (
	"context"
	"testing"

	promomodel "github.com/perfect-panel/server/internal/model/promo"
	"github.com/perfect-panel/server/internal/svc"
	"github.com/perfect-panel/server/internal/types"
	"github.com/perfect-panel/server/pkg/xerr"
	pkgerrors "github.com/pkg/errors"
	"gorm.io/gorm"
)

type fakePromoModel struct {
	insertRule func(context.Context, *promomodel.Rule) error
	findRule   func(context.Context, int64) (*promomodel.Rule, error)
	updateRule func(context.Context, *promomodel.Rule) error
}

func (fakePromoModel) QueryEligibleRules(context.Context, int64, int64) ([]*promomodel.RuleWithPrice, error) {
	return nil, nil
}

func (fakePromoModel) InsertUsage(context.Context, *promomodel.Usage, ...*gorm.DB) error {
	return nil
}

func (m fakePromoModel) InsertRule(ctx context.Context, rule *promomodel.Rule) error {
	if m.insertRule != nil {
		return m.insertRule(ctx, rule)
	}
	return nil
}

func (m fakePromoModel) FindRule(ctx context.Context, id int64) (*promomodel.Rule, error) {
	if m.findRule != nil {
		return m.findRule(ctx, id)
	}
	return nil, gorm.ErrRecordNotFound
}

func (m fakePromoModel) UpdateRule(ctx context.Context, rule *promomodel.Rule) error {
	if m.updateRule != nil {
		return m.updateRule(ctx, rule)
	}
	return nil
}

func (fakePromoModel) DeleteRule(context.Context, int64) error {
	return nil
}

func (fakePromoModel) QueryRuleList(context.Context, int, int, string, *bool, string) (int64, []*promomodel.Rule, error) {
	return 0, nil, nil
}

func (fakePromoModel) UpsertPrices(context.Context, int64, []*promomodel.SubscribePromo) error {
	return nil
}

func (fakePromoModel) FindPrice(context.Context, int64) (*promomodel.SubscribePromo, error) {
	return nil, gorm.ErrRecordNotFound
}

func (fakePromoModel) DeletePrice(context.Context, int64) error {
	return nil
}

func (fakePromoModel) QueryPriceList(context.Context, promomodel.PriceFilter) (int64, []*promomodel.SubscribePromo, error) {
	return 0, nil, nil
}

func (fakePromoModel) QueryUsageList(context.Context, promomodel.UsageFilter) (int64, []*promomodel.Usage, error) {
	return 0, nil, nil
}

func (fakePromoModel) Transaction(context.Context, func(*gorm.DB) error) error {
	return nil
}

func TestDeleteRuleNotFoundReturns404(t *testing.T) {
	svcCtx := &svc.ServiceContext{PromoModel: fakePromoModel{}}
	err := NewDeleteRuleLogic(context.Background(), svcCtx).DeleteRule(&types.DeletePromoRuleRequest{Id: 1})
	assertCodeError(t, err, 404)
}

func TestDeletePriceNotFoundReturns404(t *testing.T) {
	svcCtx := &svc.ServiceContext{PromoModel: fakePromoModel{}}
	err := NewDeletePriceLogic(context.Background(), svcCtx).DeletePrice(&types.DeletePromoPriceRequest{Id: 1})
	assertCodeError(t, err, 404)
}

func assertCodeError(t *testing.T, err error, want uint32) {
	t.Helper()
	if err == nil {
		t.Fatal("expected error")
	}
	codeErr, ok := pkgerrors.Cause(err).(*xerr.CodeError)
	if !ok {
		t.Fatalf("expected CodeError, got %T", pkgerrors.Cause(err))
	}
	if got := codeErr.GetErrCode(); got != want {
		t.Fatalf("unexpected error code: got %d want %d", got, want)
	}
}
