package grpc

import (
	"context"

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

// GetBalances 返回用户多资产余额投影。
func (s *Server) GetBalances(ctx context.Context, req *walletv1.GetBalancesRequest) (*walletv1.GetBalancesResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetAppCode())
	balances, err := s.svc.GetBalances(ctx, req.GetUserId(), req.GetAssetTypes())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}

	response := &walletv1.GetBalancesResponse{Balances: make([]*walletv1.AssetBalance, 0, len(balances))}
	for _, balance := range balances {
		response.Balances = append(response.Balances, &walletv1.AssetBalance{
			AppCode:         balance.AppCode,
			AssetType:       balance.AssetType,
			AvailableAmount: balance.AvailableAmount,
			FrozenAmount:    balance.FrozenAmount,
			Version:         balance.Version,
		})
	}

	return response, nil
}

// GetWalletOverview 返回钱包首页摘要，供我的页和钱包二级页复用。
func (s *Server) GetWalletOverview(ctx context.Context, req *walletv1.GetWalletOverviewRequest) (*walletv1.GetWalletOverviewResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetAppCode())
	overview, err := s.svc.GetWalletOverview(ctx, req.GetUserId())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.GetWalletOverviewResponse{
		Balances:     balancesToProto(overview.Balances),
		FeatureFlags: walletFeatureFlagsToProto(overview.FeatureFlags),
	}, nil
}

// GetWalletValueSummary 返回我的页钱包卡片最小金币余额。
func (s *Server) GetWalletValueSummary(ctx context.Context, req *walletv1.GetWalletValueSummaryRequest) (*walletv1.GetWalletValueSummaryResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetAppCode())
	summary, err := s.svc.GetWalletValueSummary(ctx, req.GetUserId())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.GetWalletValueSummaryResponse{Summary: &walletv1.WalletValueSummary{
		CoinAmount:  summary.CoinAmount,
		UpdatedAtMs: summary.UpdatedAtMS,
	}}, nil
}

// GetUserGiftWall 返回当前用户收到礼物的聚合墙；调用方负责限定 user_id 为当前登录用户。
func (s *Server) GetUserGiftWall(ctx context.Context, req *walletv1.GetUserGiftWallRequest) (*walletv1.GetUserGiftWallResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetAppCode())
	wall, err := s.svc.GetUserGiftWall(ctx, req.GetUserId())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &walletv1.GetUserGiftWallResponse{
		Items:             make([]*walletv1.GiftWallItem, 0, len(wall.Items)),
		GiftKindCount:     wall.GiftKindCount,
		GiftTotalCount:    wall.GiftTotalCount,
		TotalValue:        wall.TotalValue,
		TotalCoinValue:    wall.TotalCoinValue,
		TotalDiamondValue: wall.TotalDiamondValue,
		TotalGiftPoint:    wall.TotalGiftPoint,
		TotalHeatValue:    wall.TotalHeatValue,
	}
	for _, item := range wall.Items {
		resp.Items = append(resp.Items, giftWallItemToProto(item))
	}
	return resp, nil
}

// GetDiamondExchangeConfig 返回钻石兑换配置。
func (s *Server) GetDiamondExchangeConfig(ctx context.Context, req *walletv1.GetDiamondExchangeConfigRequest) (*walletv1.GetDiamondExchangeConfigResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetAppCode())
	rules, err := s.svc.GetDiamondExchangeConfig(ctx, req.GetUserId())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &walletv1.GetDiamondExchangeConfigResponse{Rules: make([]*walletv1.DiamondExchangeRule, 0, len(rules))}
	for _, rule := range rules {
		resp.Rules = append(resp.Rules, &walletv1.DiamondExchangeRule{
			ExchangeType:  rule.ExchangeType,
			FromAssetType: rule.FromAssetType,
			ToAssetType:   rule.ToAssetType,
			FromAmount:    rule.FromAmount,
			ToAmount:      rule.ToAmount,
			Enabled:       rule.Enabled,
		})
	}
	return resp, nil
}

// ListWalletTransactions 返回当前用户钱包流水。
func (s *Server) ListWalletTransactions(ctx context.Context, req *walletv1.ListWalletTransactionsRequest) (*walletv1.ListWalletTransactionsResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetAppCode())
	items, total, err := s.svc.ListWalletTransactions(ctx, ledger.ListWalletTransactionsQuery{
		AppCode:   req.GetAppCode(),
		UserID:    req.GetUserId(),
		AssetType: req.GetAssetType(),
		Page:      req.GetPage(),
		PageSize:  req.GetPageSize(),
		StartAtMS: req.GetStartAtMs(),
		EndAtMS:   req.GetEndAtMs(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return walletTransactionsToProto(items, total), nil
}

// ListHostPeriodDiamondTransactions 返回主播周期钻石收入明细，协议形状与钱包流水一致但数据源保持独立。
func (s *Server) ListHostPeriodDiamondTransactions(ctx context.Context, req *walletv1.ListWalletTransactionsRequest) (*walletv1.ListWalletTransactionsResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetAppCode())
	items, total, err := s.svc.ListHostPeriodDiamondTransactions(ctx, ledger.ListWalletTransactionsQuery{
		AppCode:   req.GetAppCode(),
		UserID:    req.GetUserId(),
		Page:      req.GetPage(),
		PageSize:  req.GetPageSize(),
		StartAtMS: req.GetStartAtMs(),
		EndAtMS:   req.GetEndAtMs(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return walletTransactionsToProto(items, total), nil
}

func walletTransactionsToProto(items []ledger.WalletTransaction, total int64) *walletv1.ListWalletTransactionsResponse {
	resp := &walletv1.ListWalletTransactionsResponse{Transactions: make([]*walletv1.WalletTransaction, 0, len(items)), Total: total}
	for _, item := range items {
		resp.Transactions = append(resp.Transactions, &walletv1.WalletTransaction{
			EntryId:              item.EntryID,
			TransactionId:        item.TransactionID,
			BizType:              item.BizType,
			AssetType:            item.AssetType,
			AvailableDelta:       item.AvailableDelta,
			FrozenDelta:          item.FrozenDelta,
			AvailableAfter:       item.AvailableAfter,
			FrozenAfter:          item.FrozenAfter,
			CounterpartyUserId:   item.CounterpartyUserID,
			RoomId:               item.RoomID,
			CreatedAtMs:          item.CreatedAtMS,
			TransferUsdMinor:     item.TransferUSDMinor,
			TransferCurrencyCode: item.TransferCurrencyCode,
			EntryRole:            item.EntryRole,
			HostBaseAmount:       item.HostBaseAmount,
			AgencyAmount:         item.AgencyAmount,
			PolicyId:             item.PolicyID,
			PolicyVersion:        item.PolicyVersion,
			RatioPointAmount:     item.RatioPointAmount,
			RatioCoinAmount:      item.RatioCoinAmount,
			GrossUsdMinor:        item.GrossUSDMinor,
			FeeUsdMinor:          item.FeeUSDMinor,
			NetUsdMinor:          item.NetUSDMinor,
			WithdrawFeeBps:       item.WithdrawFeeBPS,
		})
	}
	return resp
}

func balancesToProto(balances []ledger.AssetBalance) []*walletv1.AssetBalance {
	items := make([]*walletv1.AssetBalance, 0, len(balances))
	for _, balance := range balances {
		items = append(items, balanceToProto(balance))
	}
	return items
}

func balanceToProto(balance ledger.AssetBalance) *walletv1.AssetBalance {
	return &walletv1.AssetBalance{
		AppCode:         balance.AppCode,
		AssetType:       balance.AssetType,
		AvailableAmount: balance.AvailableAmount,
		FrozenAmount:    balance.FrozenAmount,
		Version:         balance.Version,
	}
}

func giftWallItemToProto(item ledger.GiftWallItem) *walletv1.GiftWallItem {
	return &walletv1.GiftWallItem{
		GiftId:               item.GiftID,
		GiftName:             item.GiftName,
		ResourceId:           item.ResourceID,
		Resource:             giftWallResourceToProto(item.Resource),
		ResourceSnapshotJson: item.ResourceSnapshotJSON,
		GiftTypeCode:         item.GiftTypeCode,
		PresentationJson:     item.PresentationJSON,
		GiftCount:            item.GiftCount,
		TotalValue:           item.TotalValue,
		TotalCoinValue:       item.TotalCoinValue,
		TotalDiamondValue:    item.TotalDiamondValue,
		TotalGiftPoint:       item.TotalGiftPoint,
		TotalHeatValue:       item.TotalHeatValue,
		ChargeAssetType:      item.ChargeAssetType,
		LastPriceVersion:     item.LastPriceVersion,
		FirstReceivedAtMs:    item.FirstReceivedAtMS,
		LastReceivedAtMs:     item.LastReceivedAtMS,
		SortOrder:            item.SortOrder,
	}
}

func giftWallResourceToProto(resource ledger.GiftWallResource) *walletv1.Resource {
	if resource.ResourceID == 0 {
		return nil
	}
	return &walletv1.Resource{
		AppCode:           resource.AppCode,
		ResourceId:        resource.ResourceID,
		ResourceCode:      resource.ResourceCode,
		ResourceType:      resource.ResourceType,
		Name:              resource.Name,
		Status:            resource.Status,
		Grantable:         resource.Grantable,
		GrantStrategy:     resource.GrantStrategy,
		WalletAssetType:   resource.WalletAssetType,
		WalletAssetAmount: resource.WalletAssetAmount,
		UsageScopes:       resource.UsageScopes,
		AssetUrl:          resource.AssetURL,
		PreviewUrl:        resource.PreviewURL,
		AnimationUrl:      resource.AnimationURL,
		MetadataJson:      resource.MetadataJSON,
		SortOrder:         resource.SortOrder,
		CreatedAtMs:       resource.CreatedAtMS,
		UpdatedAtMs:       resource.UpdatedAtMS,
	}
}

func walletFeatureFlagsToProto(flags ledger.WalletFeatureFlags) *walletv1.WalletFeatureFlags {
	return &walletv1.WalletFeatureFlags{
		RechargeEnabled:        flags.RechargeEnabled,
		DiamondExchangeEnabled: flags.DiamondExchangeEnabled,
	}
}
