package service

import (
	"time"

	"google.golang.org/protobuf/proto"
	roomv1 "hyapp.local/api/proto/room/v1"
	"hyapp/pkg/xerr"
	"hyapp/services/room-service/internal/room/command"
)

func marshalMutationResult(result mutationResult) ([]byte, error) {
	if result.giftV2 == nil {
		return nil, nil
	}
	payload, err := proto.Marshal(result.giftV2)
	if err != nil {
		return nil, xerr.New(xerr.Internal, "send gift v2 result cannot be encoded")
	}
	return payload, nil
}

func replayMutationResult(record CommandRecord, snapshot *roomv1.RoomSnapshot) (mutationResult, error) {
	result := mutationResult{snapshot: snapshot}
	if record.CommandType != (command.SendGift{}).Type() || len(record.ResultPayload) == 0 {
		// 历史命令没有 typed result；继续返回当前 snapshot，保持 V1 已上线行为，不伪造账务字段。
		return result, nil
	}
	var stored roomv1.SendGiftResultV2
	if err := proto.Unmarshal(record.ResultPayload, &stored); err != nil {
		// 已提交结果损坏时必须 fail-close，不能重跑 wallet 或幸运礼物来“修复”一个已提交命令。
		return mutationResult{}, xerr.New(xerr.Internal, "stored send gift result cannot be decoded")
	}
	replayed := proto.Clone(&stored).(*roomv1.SendGiftResultV2)
	replayed.IdempotentReplay = true
	replayed.OperationStatus = GiftOperationStatusCommitted
	result.billingReceiptID = replayed.GetBillingReceiptId()
	result.coinBalanceAfter = replayed.GetCoinBalanceAfter()
	result.giftIncomeBalanceAfter = replayed.GetGiftIncomeBalanceAfter()
	result.roomHeat = replayed.GetRoomHeat()
	result.giftRank = cloneGiftRankItems(replayed.GetGiftRank())
	result.luckyGift = replayed.GetLuckyGift()
	result.luckyGifts = append([]*roomv1.LuckyGiftDrawResult(nil), replayed.GetLuckyGifts()...)
	result.batchDisplay = replayed.GetBatchDisplay()
	result.giftV2 = replayed
	return result, nil
}

func cloneGiftRankItems(items []*roomv1.RankItem) []*roomv1.RankItem {
	out := make([]*roomv1.RankItem, 0, len(items))
	for _, item := range items {
		if item != nil {
			out = append(out, proto.Clone(item).(*roomv1.RankItem))
		}
	}
	return out
}

func luckyHitsFromResults(results []*roomv1.LuckyGiftDrawResult) []*roomv1.SendGiftLuckyHit {
	hits := make([]*roomv1.SendGiftLuckyHit, 0)
	for _, result := range results {
		if result == nil {
			continue
		}
		for _, hit := range result.GetHits() {
			if hit != nil && hit.GetRewardCoins() > 0 {
				hits = append(hits, proto.Clone(hit).(*roomv1.SendGiftLuckyHit))
			}
		}
	}
	return hits
}

func giftOperationCommitForResult(cmd command.Command, resultPayload []byte, now time.Time) *GiftOperationCommit {
	if cmd == nil || cmd.Type() != (command.SendGift{}).Type() || len(resultPayload) == 0 {
		return nil
	}
	return &GiftOperationCommit{
		CommandID:     cmd.ID(),
		ResultPayload: resultPayload,
		UpdatedAtMS:   now.UnixMilli(),
	}
}
