package service

import (
	"context"
	"time"

	"hyapp/pkg/xerr"
	"hyapp/services/room-service/internal/room/outbox"
	"hyapp/services/room-service/internal/room/rank"
	"hyapp/services/room-service/internal/room/state"

	roomv1 "hyapp.local/api/proto/room/v1"
)

const (
	maxGiftTargetsPerCommand    = 30
	maxGiftComboSessionIDLength = 128
)

// SendGift 先同步调用 wallet，再在 Room Cell 内完成热度、榜单和房间事件落地。
func (s *Service) SendGift(ctx context.Context, req *roomv1.SendGiftRequest) (*roomv1.SendGiftResponse, error) {
	return s.sendGift(ctx, req, giftSendOptions{})
}

// SendGiftBatch 是多人送礼展示入口；它复用送礼账务、幸运礼物和 Room Cell 提交流程，
// 但只在 batch 分支生成 RoomGiftBatchSent 展示消息，避免普通 SendGift 被 display_mode 隐式改变行为。
func (s *Service) SendGiftBatch(ctx context.Context, req *roomv1.SendGiftRequest) (*roomv1.SendGiftResponse, error) {
	return s.sendGiftBatch(ctx, req)
}

func (s *Service) sendGiftBatch(ctx context.Context, req *roomv1.SendGiftRequest) (*roomv1.SendGiftResponse, error) {
	return s.sendGift(ctx, req, giftSendOptions{BatchDisplay: true})
}

type giftSendOptions struct {
	Robot        robotGiftOptions
	BatchDisplay bool
}

func (s *Service) sendGift(ctx context.Context, req *roomv1.SendGiftRequest, options giftSendOptions) (*roomv1.SendGiftResponse, error) {
	return s.sendGiftWithRecovery(ctx, req, options, GiftOperation{})
}

func (s *Service) sendGiftWithRecovery(ctx context.Context, req *roomv1.SendGiftRequest, options giftSendOptions, recovery GiftOperation) (*roomv1.SendGiftResponse, error) {
	if options.Robot.Enabled && recovery.CommandID == "" {
		// 新机器人礼物只能走 RobotSendGift 的纯展示通道。这里 fail-close，防止后续调用方误把机器人重新接回
		// room_gift_operations、Room Cell 持久化、钱包账本或 MQ；已有历史 saga 恢复不依赖 options.Robot。
		return nil, xerr.New(xerr.InvalidArgument, "robot gift must use display-only path")
	}
	ctx = contextFromMeta(ctx, req.GetMeta())
	flow := newGiftFlow(s, ctx, req, options)
	if recovery.CommandID != "" {
		if err := flow.resumeGiftOperation(recovery); err != nil {
			return nil, err
		}
	} else if err := flow.loadGiftOperation(); err != nil {
		return nil, err
	}

	result, err := s.mutateRoom(ctx, flow.cmd, true, func(now time.Time, current *state.RoomState, localRank *rank.LocalRank) (mutationResult, []outbox.Record, error) {
		// 阶段顺序保持原 sendGift 同步主链路：先校验房间态，再取房间事实，再扣费/抽奖，最后提交 Room Cell 状态和构造事件。
		if err := flow.validateBeforeDebit(current); err != nil {
			return mutationResult{}, nil, err
		}
		if err := flow.prepareRoomFacts(); err != nil {
			return mutationResult{}, nil, err
		}
		if err := flow.ensureGiftOperation(now); err != nil {
			return mutationResult{}, nil, err
		}
		if err := flow.debitAndSettle(now); err != nil {
			return mutationResult{}, nil, err
		}
		if err := flow.applyRoomState(now, current, localRank); err != nil {
			return mutationResult{}, nil, err
		}
		return flow.buildMutationResult(now, current)
	})
	if err != nil {
		flow.handleGiftOperationFailure(err)
		return nil, err
	}

	return &roomv1.SendGiftResponse{
		Result:                 commandResult(result.applied, result.snapshot.GetVersion(), s.clock.Now()),
		BillingReceiptId:       result.billingReceiptID,
		RoomHeat:               result.roomHeat,
		GiftRank:               result.giftRank,
		Room:                   result.snapshot,
		Rocket:                 result.snapshot.GetRocket(),
		LuckyGift:              result.luckyGift,
		LuckyGifts:             result.luckyGifts,
		CoinBalanceAfter:       result.coinBalanceAfter,
		GiftIncomeBalanceAfter: result.giftIncomeBalanceAfter,
		BatchDisplay:           result.batchDisplay,
		V2:                     result.giftV2,
	}, nil
}
