package service

import (
	"context"
	"strings"
	"time"

	roomv1 "hyapp.local/api/proto/room/v1"
	walletv1 "hyapp.local/api/proto/wallet/v1"
	"hyapp/pkg/appcode"
	"hyapp/pkg/xerr"
	"hyapp/services/room-service/internal/room/command"
	"hyapp/services/room-service/internal/room/outbox"
	"hyapp/services/room-service/internal/room/rank"
	"hyapp/services/room-service/internal/room/state"
)

// ApplyRoomRPSGift 把 room-rps 最终由败者支付的一份礼物应用到火箭。
// 钱包已由 game-service 结算，因此本入口只接受服务端锁定的 heat_value，并用 command_id 保证重试不重复充能。
func (s *Service) ApplyRoomRPSGift(ctx context.Context, req *roomv1.ApplyRoomRPSGiftRequest) (*roomv1.ApplyRoomRPSGiftResponse, error) {
	ctx = contextFromMeta(ctx, req.GetMeta())
	if req.GetSenderUserId() <= 0 || req.GetTargetUserId() <= 0 || strings.TrimSpace(req.GetGiftId()) == "" || req.GetHeatValue() <= 0 {
		return nil, xerr.New(xerr.InvalidArgument, "room rps settled gift is incomplete")
	}
	cmd := command.ApplyRoomRPSGift{
		Base:         baseFromMeta(req.GetMeta()),
		TargetUserID: req.GetTargetUserId(),
		GiftID:       strings.TrimSpace(req.GetGiftId()),
		HeatValue:    req.GetHeatValue(),
	}
	cmd.Base.Room = strings.TrimSpace(req.GetRoomId())
	cmd.Base.ActorID = req.GetSenderUserId()

	result, err := s.mutateRoom(ctx, cmd, true, func(now time.Time, current *state.RoomState, _ *rank.LocalRank) (mutationResult, []outbox.Record, error) {
		roomMeta, exists, err := s.repository.GetRoomMeta(ctx, cmd.RoomID())
		if err != nil {
			return mutationResult{}, nil, err
		}
		if !exists {
			return mutationResult{}, nil, xerr.New(xerr.NotFound, "room not found")
		}
		cfg, err := s.roomRocketConfig(ctx)
		if err != nil {
			return mutationResult{}, nil, err
		}
		// 复用普通送礼的唯一火箭规则实现，但不进入钱包、房间热度、礼物榜或 RoomGiftSent 链路。
		giftCmd := command.SendGift{Base: cmd.Base, TargetUserID: cmd.TargetUserID, TargetUserIDs: []int64{cmd.TargetUserID}, GiftID: cmd.GiftID, GiftCount: 1, HeatValue: cmd.HeatValue}
		settledGift := giftCmd
		billing := &walletv1.DebitGiftResponse{HeatValue: cmd.HeatValue}
		rocketApply, err := s.applyRoomRocketGift(now, current, cfg, giftCmd, &settledGift, billing, roomMeta)
		if err != nil {
			return mutationResult{}, nil, err
		}
		copyRoomRPSRocketSnapshot(&cmd, settledGift)
		payload, err := command.Serialize(cmd)
		if err != nil {
			return mutationResult{}, nil, err
		}
		current.Version++

		records := make([]outbox.Record, 0, 1)
		var progress *roomRocketProgressPending
		if rocketApply.progressEvent != nil {
			progressRecord, err := outbox.Build(current.RoomID, "RoomRocketFuelChanged", current.Version, now, rocketApply.progressEvent)
			if err != nil {
				return mutationResult{}, nil, err
			}
			progressRecord.AppCode = appcode.FromContext(ctx)
			if progressRecord.Envelope != nil {
				progressRecord.Envelope.AppCode = progressRecord.AppCode
			}
			progress = &roomRocketProgressPending{record: progressRecord, rocketID: rocketApply.progressEvent.GetRocketId(), level: rocketApply.progressEvent.GetLevel(), currentFuel: rocketApply.progressEvent.GetCurrentFuel(), roomVersion: current.Version}
		}
		if rocketApply.ignited != nil {
			// RPS 礼物同样可能触发跨房火箭飘屏，点火事实使用当前 Room Cell 内的锁房快照。
			rocketApply.ignited.RoomLocked = strings.TrimSpace(current.RoomPasswordHash) != ""
			ignitedRecord, err := outbox.Build(current.RoomID, "RoomRocketIgnited", current.Version, now, rocketApply.ignited)
			if err != nil {
				return mutationResult{}, nil, err
			}
			records = append(records, ignitedRecord)
		}
		return mutationResult{snapshot: current.ToProto(), commandPayload: payload, roomRocketProgress: progress}, records, nil
	})
	if err != nil {
		return nil, err
	}
	return &roomv1.ApplyRoomRPSGiftResponse{Result: commandResult(result.applied, result.snapshot.GetVersion(), s.clock.Now()), Rocket: result.snapshot.GetRocket()}, nil
}

func copyRoomRPSRocketSnapshot(target *command.ApplyRoomRPSGift, source command.SendGift) {
	target.RocketTouched = source.RocketTouched
	target.RocketAddedFuel = source.RocketAddedFuel
	target.RocketEffectiveFuel = source.RocketEffectiveFuel
	target.RocketOverflowFuel = source.RocketOverflowFuel
	target.RocketLevel = source.RocketLevel
	target.RocketFuel = source.RocketFuel
	target.RocketStatus = source.RocketStatus
	target.RocketFuelThreshold = source.RocketFuelThreshold
	target.RocketIgnitedAtMS = source.RocketIgnitedAtMS
	target.RocketLaunchAtMS = source.RocketLaunchAtMS
	target.RocketResetAtMS = source.RocketResetAtMS
	target.RocketTop1UserID = source.RocketTop1UserID
	target.RocketIgniterUserID = source.RocketIgniterUserID
	target.RocketID = source.RocketID
	target.RocketConfigVersion = source.RocketConfigVersion
	target.RocketPendingLaunches = source.RocketPendingLaunches
	target.RocketCurrentContributions = source.RocketCurrentContributions
}
