package grpc

import (
	"context"

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

// ListPointWithdrawalCoinSellers 返回 wallet 侧已执行 app/status/区域或国家过滤的可信白名单。
func (s *Server) ListPointWithdrawalCoinSellers(ctx context.Context, req *walletv1.ListPointWithdrawalCoinSellersRequest) (*walletv1.ListPointWithdrawalCoinSellersResponse, error) {
	items, err := s.svc.ListPointWithdrawalCoinSellers(ctx, req.GetAppCode(), req.GetRegionId(), req.GetCountryCode(), req.GetIncludeDisabled())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	response := &walletv1.ListPointWithdrawalCoinSellersResponse{Sellers: make([]*walletv1.PointWithdrawalCoinSellerConfig, 0, len(items))}
	for _, item := range items {
		response.Sellers = append(response.Sellers, &walletv1.PointWithdrawalCoinSellerConfig{
			AppCode: item.AppCode, SellerUserId: item.SellerUserID, SortOrder: int32(item.SortOrder),
			PointAmount: item.PointAmount, SellerCoinAmount: item.SellerCoinAmount,
			ServiceRegionIds:    append([]int64(nil), item.ServiceRegionIDs...),
			ServiceCountryCodes: append([]string(nil), item.ServiceCountryCodes...), Status: item.Status,
			CreatedAtMs: item.CreatedAtMS, UpdatedAtMs: item.UpdatedAtMS,
		})
	}
	return response, nil
}

// TransferPointToCoinSeller 不接受兑换比例字段，确保所有调用方都只能使用数据库白名单快照。
func (s *Server) TransferPointToCoinSeller(ctx context.Context, req *walletv1.TransferPointToCoinSellerRequest) (*walletv1.TransferPointToCoinSellerResponse, error) {
	receipt, err := s.svc.TransferPointToCoinSeller(ctx, ledger.PointToCoinSellerCommand{
		AppCode: req.GetAppCode(), CommandID: req.GetCommandId(), SourceUserID: req.GetSourceUserId(),
		SellerUserID: req.GetSellerUserId(), PointAmount: req.GetPointAmount(),
		SourceAssetType: req.GetSourceAssetType(), GrossUSDMinor: req.GetGrossUsdMinor(),
		SourceCountryCode: req.GetSourceCountryCode(), Reason: req.GetReason(),
		RegionID: req.GetRegionId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.TransferPointToCoinSellerResponse{
		TransactionId: receipt.TransactionID, SourcePointBalanceAfter: receipt.SourcePointBalanceAfter,
		SellerBalanceAfter: receipt.SellerBalanceAfter, PointAmount: receipt.PointAmount,
		SellerCoinAmount: receipt.SellerCoinAmount, RatioPointAmount: receipt.RatioPointAmount,
		RatioSellerCoinAmount: receipt.RatioSellerCoinAmount,
		SourceAssetType:       receipt.SourceAssetType, GrossUsdMinor: receipt.GrossUSDMinor,
		FeeUsdMinor: receipt.FeeUSDMinor, NetUsdMinor: receipt.NetUSDMinor, WithdrawFeeBps: receipt.WithdrawFeeBPS,
		PolicyId: receipt.PolicyID, PolicyVersion: receipt.PolicyVersion,
	}, nil
}

// ExchangePointToCoin 把 H5 的钻石输入解释为 POINT，并返回 wallet-service 原子账变后的余额快照。
func (s *Server) ExchangePointToCoin(ctx context.Context, req *walletv1.ExchangePointToCoinRequest) (*walletv1.ExchangePointToCoinResponse, error) {
	receipt, err := s.svc.ExchangePointToCoin(ctx, ledger.PointToCoinCommand{
		AppCode: req.GetAppCode(), CommandID: req.GetCommandId(), UserID: req.GetUserId(), PointAmount: req.GetPointAmount(),
		SourceAssetType: req.GetSourceAssetType(), RegionID: req.GetRegionId(), NowMS: req.GetNowMs(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.ExchangePointToCoinResponse{
		TransactionId: receipt.TransactionID, PointAmount: receipt.PointAmount, CoinAmount: receipt.CoinAmount,
		PointBalanceAfter: receipt.PointBalanceAfter, CoinBalanceAfter: receipt.CoinBalanceAfter,
		RatioPointAmount: receipt.RatioPointAmount, RatioCoinAmount: receipt.RatioCoinAmount,
		SourceAssetType: receipt.SourceAssetType, PolicyId: receipt.PolicyID, PolicyVersion: receipt.PolicyVersion,
	}, nil
}

// GetPointWithdrawalConfig 暴露 POINT 提现和兑换所需的最小运行参数，H5 不解析 Admin rule_json。
func (s *Server) GetPointWithdrawalConfig(ctx context.Context, req *walletv1.GetPointWithdrawalConfigRequest) (*walletv1.GetPointWithdrawalConfigResponse, error) {
	var config ledger.PointWithdrawalRuntimeConfig
	var err error
	if req.GetUserId() > 0 {
		config, err = s.svc.GetPointWithdrawalConfigForUser(ctx, req.GetAppCode(), req.GetUserId(), req.GetRegionId(), req.GetNowMs(), req.GetAssetType())
	} else {
		config, err = s.svc.GetPointWithdrawalConfigForAsset(ctx, req.GetAppCode(), req.GetRegionId(), req.GetNowMs(), req.GetAssetType())
	}
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.GetPointWithdrawalConfigResponse{
		Found: config.Found, PointsPerUsd: config.PointsPerUSD, CoinsPerUsd: config.CoinsPerUSD, FeeBps: int32(config.FeeBPS),
		MinimumPoints: config.MinimumPoints, PolicyInstanceCode: config.PolicyInstanceCode,
		PolicyType: config.PolicyType, MinimumWithdrawUsdMinor: config.MinimumWithdrawUSDMinor,
		CoinSellerMinimumWithdrawUsdMinor: config.CoinSellerMinimumWithdrawUSDMinor,
		PlatformMinimumWithdrawUsdMinor:   config.PlatformMinimumWithdrawUSDMinor,
		DiamondExchangeEnabled:            &config.DiamondExchangeEnabled,
		AgencyPointShareBps:               config.AgencyPointShareBPS, PolicyId: config.PolicyID, PolicyVersion: config.PolicyVersion,
		AvailabilityEvaluated:  config.AvailabilityEvaluated,
		CoinSellerAvailability: pointWithdrawalAvailabilityToProto(config.CoinSellerAvailability),
		PlatformAvailability:   pointWithdrawalAvailabilityToProto(config.PlatformAvailability),
	}, nil
}

func pointWithdrawalAvailabilityToProto(value ledger.PointWithdrawalActionAvailability) *walletv1.PointWithdrawalActionAvailability {
	return &walletv1.PointWithdrawalActionAvailability{
		Allowed: value.Allowed, LimitPeriod: value.LimitPeriod, LimitCount: value.LimitCount,
		UsedCount: value.UsedCount, RemainingCount: value.RemainingCount,
		AllowedDays: value.AllowedDays, BlockReason: value.BlockReason,
	}
}
