package luckygiftmq

import (
	"encoding/json"
	"testing"

	"google.golang.org/protobuf/proto"
	luckygifteventsv1 "hyapp.local/api/proto/events/luckygift/v1"
)

func TestLuckyGiftOutboxMessageRoundTrip(t *testing.T) {
	envelope := validLuckyGiftEnvelope(t)
	body, err := EncodeLuckyGiftOutboxMessage(envelope)
	if err != nil {
		t.Fatalf("EncodeLuckyGiftOutboxMessage failed: %v", err)
	}

	decoded, message, err := DecodeLuckyGiftOutboxMessage(body)
	if err != nil {
		t.Fatalf("DecodeLuckyGiftOutboxMessage failed: %v", err)
	}
	if !proto.Equal(decoded, envelope) {
		t.Fatalf("decoded envelope mismatch: got=%v want=%v", decoded, envelope)
	}
	if message.MessageType != MessageTypeLuckyGiftOutboxEvent || message.EventType != EventTypeLuckyGiftDrawn || message.DrawID != "draw-1" {
		t.Fatalf("decoded wrapper metadata mismatch: %+v", message)
	}
}

func TestLuckyGiftOutboxMessageRejectsWrapperEnvelopeDrift(t *testing.T) {
	envelope := validLuckyGiftEnvelope(t)
	body, err := EncodeLuckyGiftOutboxMessage(envelope)
	if err != nil {
		t.Fatalf("EncodeLuckyGiftOutboxMessage failed: %v", err)
	}
	var message LuckyGiftOutboxMessage
	if err := json.Unmarshal(body, &message); err != nil {
		t.Fatalf("decode wrapper: %v", err)
	}
	message.DrawID = "draw-other"
	tampered, err := json.Marshal(message)
	if err != nil {
		t.Fatalf("encode tampered wrapper: %v", err)
	}
	if _, _, err := DecodeLuckyGiftOutboxMessage(tampered); err == nil {
		t.Fatal("wrapper/envelope drift must be rejected")
	}
}

func TestLuckyGiftOutboxMessageRejectsUnsettledFact(t *testing.T) {
	envelope := validLuckyGiftEnvelope(t)
	var drawn luckygifteventsv1.LuckyGiftDrawn
	if err := proto.Unmarshal(envelope.GetBody(), &drawn); err != nil {
		t.Fatalf("decode lucky body: %v", err)
	}
	drawn.RewardStatus = "pending"
	body, err := proto.Marshal(&drawn)
	if err != nil {
		t.Fatalf("encode pending lucky body: %v", err)
	}
	envelope.Body = body
	if _, err := EncodeLuckyGiftOutboxMessage(envelope); err == nil {
		t.Fatal("pending reward must not be published as LuckyGiftDrawn")
	}
}

func TestLuckyGiftEventTypeTagAndDisplayBoundary(t *testing.T) {
	tag, err := EventTypeTag(EventTypeLuckyGiftDrawn)
	if err != nil || tag != TagLuckyGiftDrawn {
		t.Fatalf("EventTypeTag result: tag=%q err=%v", tag, err)
	}
	if _, err := EventTypeTag("LuckyGiftUnknown"); err == nil {
		t.Fatal("unsupported lucky gift event type must be rejected")
	}
	if LuckyGiftDisplayMinMultiplierPPM != 10_000_000 {
		t.Fatalf("display threshold=%d, want exact 10x ppm", LuckyGiftDisplayMinMultiplierPPM)
	}
}

func validLuckyGiftEnvelope(t *testing.T) *luckygifteventsv1.EventEnvelope {
	t.Helper()
	const drawCreatedAtMS int64 = 1_783_940_398_274
	drawn := &luckygifteventsv1.LuckyGiftDrawn{
		DrawId:                    "draw-1",
		CommandId:                 "command-1",
		RoomId:                    "room-1",
		PoolId:                    "default",
		GiftId:                    "43",
		GiftCount:                 1,
		SenderUserId:              123456,
		TargetUserId:              654321,
		SenderName:                "Lucky User",
		SenderAvatar:              "https://cdn.example/avatar.png",
		SenderDisplayUserId:       "123456",
		SenderPrettyDisplayUserId: "888888",
		VisibleRegionId:           1,
		CountryId:                 86,
		CoinSpent:                 100,
		RuleVersion:               7,
		ExperiencePool:            "normal",
		SelectedTierId:            "normal_50x",
		MultiplierPpm:             50_000_000,
		BaseRewardCoins:           5_000,
		EffectiveRewardCoins:      5_000,
		HighMultiplier:            true,
		RewardStatus:              "granted",
		WalletTransactionId:       "wallet-tx-1",
		DrawCreatedAtMs:           drawCreatedAtMS,
		RewardGrantedAtMs:         drawCreatedAtMS + 20,
	}
	body, err := proto.Marshal(drawn)
	if err != nil {
		t.Fatalf("marshal lucky body: %v", err)
	}
	return &luckygifteventsv1.EventEnvelope{
		EventId:      "lucky_gift_drawn:draw-1",
		EventType:    EventTypeLuckyGiftDrawn,
		AppCode:      "lalu",
		DrawId:       "draw-1",
		OccurredAtMs: drawCreatedAtMS,
		Body:         body,
	}
}
