package grpc

import (
	"context"
	"testing"

	luckygiftv1 "hyapp.local/api/proto/luckygift/v1"
	domain "hyapp/services/lucky-gift-service/internal/domain/luckygift"
	service "hyapp/services/lucky-gift-service/internal/service/luckygift"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

type poolAdjustmentGRPCRepository struct {
	service.Repository
	command domain.PoolAdjustmentCommand
	result  domain.PoolAdjustmentResult
}

func (r *poolAdjustmentGRPCRepository) AdjustLuckyGiftPoolBalance(_ context.Context, command domain.PoolAdjustmentCommand, _ int64) (domain.PoolAdjustmentResult, error) {
	r.command = command
	return r.result, nil
}

func TestBatchExecuteLuckyGiftDrawRejectsMixedAppCodes(t *testing.T) {
	server := NewLuckyGiftServer(nil)
	_, err := server.BatchExecuteLuckyGiftDraw(context.Background(), &luckygiftv1.BatchExecuteLuckyGiftDrawRequest{
		LuckyGifts: []*luckygiftv1.LuckyGiftMeta{
			{Meta: &luckygiftv1.RequestMeta{AppCode: "aslan"}, CommandId: "cmd-1"},
			{Meta: &luckygiftv1.RequestMeta{AppCode: "yumi"}, CommandId: "cmd-2"},
		},
	})
	if err == nil {
		t.Fatal("expected mixed app_code batch to be rejected")
	}
}

func TestAdjustLuckyGiftPoolBalanceMapsExplicitStrategyAndSnapshot(t *testing.T) {
	repository := &poolAdjustmentGRPCRepository{result: domain.PoolAdjustmentResult{
		Adjustment: domain.PoolAdjustment{
			AdjustmentID: "adjustment-1", AppCode: "aslan", PoolID: "lucky", StrategyVersion: domain.StrategyDynamicV3,
			Direction: domain.PoolAdjustmentIn, AmountCoins: 100, BalanceBefore: 0, BalanceAfter: 100,
		},
		Pool: domain.PoolBalance{
			AppCode: "aslan", PoolID: "lucky", StrategyVersion: domain.StrategyDynamicV3,
			Balance: 100, ManualCreditTotal: 100, Materialized: true,
		},
	}}
	server := NewAdminLuckyGiftServer(service.New(repository))
	resp, err := server.AdjustLuckyGiftPoolBalance(context.Background(), &luckygiftv1.AdjustLuckyGiftPoolBalanceRequest{
		Meta:   &luckygiftv1.RequestMeta{AppCode: "aslan", RequestId: "request-1"},
		PoolId: "lucky", StrategyVersion: domain.StrategyDynamicV3, AdjustmentId: "adjustment-1",
		Direction: domain.PoolAdjustmentIn, AmountCoins: 100, Reason: "launch", OperatorAdminId: 7,
	})
	if err != nil {
		t.Fatalf("adjust pool RPC: %v", err)
	}
	if repository.command.AppCode != "aslan" || repository.command.RequestID != "request-1" || repository.command.StrategyVersion != domain.StrategyDynamicV3 {
		t.Fatalf("owner command=%+v", repository.command)
	}
	if resp.GetPool().GetStrategyVersion() != domain.StrategyDynamicV3 || resp.GetPool().GetManualCreditTotal() != 100 || resp.GetAdjustment().GetBalanceAfter() != 100 {
		t.Fatalf("RPC response=%+v", resp)
	}
}

func TestAdjustLuckyGiftPoolBalanceRejectsMissingAppCodeBeforeOwnerCall(t *testing.T) {
	server := NewAdminLuckyGiftServer(nil)
	_, err := server.AdjustLuckyGiftPoolBalance(context.Background(), &luckygiftv1.AdjustLuckyGiftPoolBalanceRequest{
		Meta: &luckygiftv1.RequestMeta{}, PoolId: "lucky", StrategyVersion: domain.StrategyDynamicV3,
		AdjustmentId: "adjustment-1", Direction: domain.PoolAdjustmentIn, AmountCoins: 1, Reason: "test", OperatorAdminId: 7,
	})
	if status.Code(err) != codes.InvalidArgument {
		t.Fatalf("missing app_code error=%v, want InvalidArgument", err)
	}
}
