package grpc

import (
	"context"

	walletv1 "hyapp.local/api/proto/wallet/v1"
	"hyapp/pkg/appcode"
	"hyapp/pkg/xerr"
	"hyapp/services/wallet-service/internal/domain/ledger"
)

// DebitGift 只负责 protobuf 转换和错误映射，扣费规则在 service/repository。
func (s *Server) DebitGift(ctx context.Context, req *walletv1.DebitGiftRequest) (*walletv1.DebitGiftResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetAppCode())
	receipt, err := s.svc.DebitGift(ctx, ledger.DebitGiftCommand{
		AppCode:        req.GetAppCode(),
		CommandID:      req.GetCommandId(),
		RoomID:         req.GetRoomId(),
		SenderUserID:   req.GetSenderUserId(),
		TargetUserID:   req.GetTargetUserId(),
		GiftID:         req.GetGiftId(),
		GiftCount:      req.GetGiftCount(),
		PriceVersion:   req.GetPriceVersion(),
		RegionID:       req.GetRegionId(),
		SenderRegionID: req.GetSenderRegionId(),
		TargetIsHost:   req.GetTargetIsHost(),

		TargetHostRegionID:      req.GetTargetHostRegionId(),
		TargetAgencyOwnerUserID: req.GetTargetAgencyOwnerUserId(),
		EntitlementID:           req.GetEntitlementId(),
		ChargeSource:            req.GetChargeSource(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}

	return debitGiftResponseFromReceipt(receipt), nil
}

// DebitDirectGift 处理私聊送礼账务命令；私聊没有房间状态，区域和主播身份必须由 gateway 注入。
func (s *Server) DebitDirectGift(ctx context.Context, req *walletv1.DebitDirectGiftRequest) (*walletv1.DebitGiftResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetAppCode())
	receipt, err := s.svc.DebitDirectGift(ctx, ledger.DebitGiftCommand{
		AppCode:        req.GetAppCode(),
		CommandID:      req.GetCommandId(),
		SenderUserID:   req.GetSenderUserId(),
		TargetUserID:   req.GetTargetUserId(),
		GiftID:         req.GetGiftId(),
		GiftCount:      req.GetGiftCount(),
		PriceVersion:   req.GetPriceVersion(),
		RegionID:       req.GetRegionId(),
		SenderRegionID: req.GetSenderRegionId(),
		TargetIsHost:   req.GetTargetIsHost(),

		TargetHostRegionID:      req.GetTargetHostRegionId(),
		TargetAgencyOwnerUserID: req.GetTargetAgencyOwnerUserId(),
		EntitlementID:           req.GetEntitlementId(),
		ChargeSource:            req.GetChargeSource(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}

	return debitGiftResponseFromReceipt(receipt), nil
}

// BatchDebitGift 只负责批量目标 protobuf 转换；同事务扣费和幂等由 wallet service/repository 保证。
func (s *Server) BatchDebitGift(ctx context.Context, req *walletv1.BatchDebitGiftRequest) (*walletv1.BatchDebitGiftResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetAppCode())
	targets := make([]ledger.DebitGiftTargetCommand, 0, len(req.GetTargets()))
	for _, target := range req.GetTargets() {
		targets = append(targets, ledger.DebitGiftTargetCommand{
			CommandID:               target.GetCommandId(),
			TargetUserID:            target.GetTargetUserId(),
			TargetIsHost:            target.GetTargetIsHost(),
			TargetHostRegionID:      target.GetTargetHostRegionId(),
			TargetAgencyOwnerUserID: target.GetTargetAgencyOwnerUserId(),
		})
	}
	receipt, err := s.svc.BatchDebitGift(ctx, ledger.BatchDebitGiftCommand{
		AppCode:        req.GetAppCode(),
		CommandID:      req.GetCommandId(),
		RoomID:         req.GetRoomId(),
		SenderUserID:   req.GetSenderUserId(),
		GiftID:         req.GetGiftId(),
		GiftCount:      req.GetGiftCount(),
		PriceVersion:   req.GetPriceVersion(),
		RegionID:       req.GetRegionId(),
		SenderRegionID: req.GetSenderRegionId(),
		Targets:        targets,
		EntitlementID:  req.GetEntitlementId(),
		ChargeSource:   req.GetChargeSource(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	response := &walletv1.BatchDebitGiftResponse{
		Aggregate: debitGiftResponseFromReceipt(receipt.Aggregate),
		Receipts:  make([]*walletv1.BatchDebitGiftReceipt, 0, len(receipt.Targets)),
	}
	for _, target := range receipt.Targets {
		response.Receipts = append(response.Receipts, &walletv1.BatchDebitGiftReceipt{
			TargetUserId: target.TargetUserID,
			CommandId:    target.CommandID,
			Billing:      debitGiftResponseFromReceipt(target.Receipt),
		})
	}
	return response, nil
}

// DebitRobotGift 扣机器人专用金币；该入口只供内部机器人房间编排链路调用。
func (s *Server) DebitRobotGift(ctx context.Context, req *walletv1.DebitRobotGiftRequest) (*walletv1.DebitGiftResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetAppCode())
	receipt, err := s.svc.DebitRobotGift(ctx, ledger.DebitGiftCommand{
		AppCode:        req.GetAppCode(),
		CommandID:      req.GetCommandId(),
		RoomID:         req.GetRoomId(),
		SenderUserID:   req.GetSenderUserId(),
		TargetUserID:   req.GetTargetUserId(),
		GiftID:         req.GetGiftId(),
		GiftCount:      req.GetGiftCount(),
		PriceVersion:   req.GetPriceVersion(),
		RegionID:       req.GetRegionId(),
		SenderRegionID: req.GetSenderRegionId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return debitGiftResponseFromReceipt(receipt), nil
}

func debitGiftResponseFromReceipt(receipt ledger.Receipt) *walletv1.DebitGiftResponse {
	return &walletv1.DebitGiftResponse{
		BillingReceiptId:            receipt.BillingReceiptID,
		BalanceAfter:                receipt.BalanceAfter,
		BalanceVersion:              receipt.BalanceVersion,
		TransactionId:               receipt.TransactionID,
		CoinSpent:                   receipt.CoinSpent,
		ChargeAssetType:             receipt.ChargeAssetType,
		ChargeAmount:                receipt.ChargeAmount,
		GiftPointAdded:              receipt.GiftPointAdded,
		HeatValue:                   receipt.HeatValue,
		GiftTypeCode:                receipt.GiftTypeCode,
		CpRelationType:              receipt.CPRelationType,
		GiftName:                    receipt.GiftName,
		GiftIconUrl:                 receipt.GiftIconURL,
		GiftAnimationUrl:            receipt.GiftAnimationURL,
		GiftEffectTypes:             receipt.GiftEffectTypes,
		PriceVersion:                receipt.PriceVersion,
		HostPeriodDiamondAdded:      receipt.HostPeriodDiamondAdded,
		HostIncomePolicyType:        receipt.HostIncomePolicyType,
		HostIncomeBalanceAfter:      receipt.HostIncomeBalanceAfter,
		IncomeAssetType:             receipt.IncomeAssetType,
		HostBaseAmount:              receipt.HostBaseAmount,
		AgencyAmount:                receipt.AgencyAmount,
		AgencyOwnerUserId:           receipt.AgencyOwnerUserID,
		AgencyIncomeBalanceAfter:    receipt.AgencyIncomeBalanceAfter,
		HostIncomePolicyId:          receipt.HostIncomePolicyID,
		HostIncomePolicyVersion:     receipt.HostIncomePolicyVersion,
		HostPolicyCoefficient:       receipt.HostPolicyCoefficient,
		AgencyPointShareBps:         receipt.AgencyPointShareBPS,
		HostPeriodCycleKey:          receipt.HostPeriodCycleKey,
		HostPointAdded:              receipt.HostPointAdded,
		HostPointBalanceAfter:       receipt.HostPointBalanceAfter,
		HostPointAssetType:          receipt.HostPointAssetType,
		HostPointPolicyInstanceCode: receipt.HostPointPolicyInstanceCode,
		HostPointTemplateCode:       receipt.HostPointTemplateCode,
		HostPointTemplateVersion:    receipt.HostPointTemplateVersion,
		EntitlementId:               receipt.EntitlementID,
		ChargeSource:                receipt.ChargeSource,
		GiftIncomeCoinAmount:        receipt.GiftIncomeCoinAmount,
		GiftIncomeBalanceAfter:      receipt.GiftIncomeBalanceAfter,
		RechargeSevenDayCoins:       receipt.RechargeSevenDayCoins,
		RechargeThirtyDayCoins:      receipt.RechargeThirtyDayCoins,
		LastRechargedAtMs:           receipt.LastRechargedAtMS,
		PaidAtMs:                    receipt.PaidAtMS,
	}
}
