package grpc

import (
	"context"

	activityv1 "hyapp.local/api/proto/activity/v1"
	"hyapp/pkg/appcode"
	"hyapp/pkg/xerr"
	domain "hyapp/services/activity-service/internal/domain/firstrecharge"
	service "hyapp/services/activity-service/internal/service/firstrecharge"
)

// FirstRechargeRewardServer 暴露 App 首冲奖励查询和内部充值事实消费入口。
type FirstRechargeRewardServer struct {
	activityv1.UnimplementedFirstRechargeRewardServiceServer

	svc *service.Service
}

func NewFirstRechargeRewardServer(svc *service.Service) *FirstRechargeRewardServer {
	return &FirstRechargeRewardServer{svc: svc}
}

func (s *FirstRechargeRewardServer) GetFirstRechargeRewardStatus(ctx context.Context, req *activityv1.GetFirstRechargeRewardStatusRequest) (*activityv1.GetFirstRechargeRewardStatusResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
	status, err := s.svc.GetStatus(ctx, req.GetUserId())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &activityv1.GetFirstRechargeRewardStatusResponse{Status: firstRechargeRewardStatusToProto(status)}, nil
}

func (s *FirstRechargeRewardServer) ConsumeFirstRechargeReward(ctx context.Context, req *activityv1.ConsumeFirstRechargeRewardRequest) (*activityv1.ConsumeFirstRechargeRewardResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
	claim, consumed, reason, err := s.svc.Consume(ctx, domain.RechargeEvent{
		AppCode:            req.GetMeta().GetAppCode(),
		EventID:            req.GetEventId(),
		TransactionID:      req.GetTransactionId(),
		CommandID:          req.GetCommandId(),
		UserID:             req.GetUserId(),
		RechargeCoinAmount: req.GetRechargeCoinAmount(),
		RechargeSequence:   req.GetRechargeSequence(),
		RechargeType:       req.GetRechargeType(),
		RechargeUSDMinor:   req.GetRechargeUsdMinor(),
		GoogleProductID:    req.GetGoogleProductId(),
		OccurredAtMS:       req.GetOccurredAtMs(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &activityv1.ConsumeFirstRechargeRewardResponse{
		Claim:    firstRechargeRewardClaimToProto(claim),
		Consumed: consumed,
		Reason:   reason,
	}, nil
}

// AdminFirstRechargeRewardServer 暴露后台配置和发放记录查询入口。
type AdminFirstRechargeRewardServer struct {
	activityv1.UnimplementedAdminFirstRechargeRewardServiceServer

	svc *service.Service
}

func NewAdminFirstRechargeRewardServer(svc *service.Service) *AdminFirstRechargeRewardServer {
	return &AdminFirstRechargeRewardServer{svc: svc}
}

func (s *AdminFirstRechargeRewardServer) GetFirstRechargeRewardConfig(ctx context.Context, req *activityv1.GetFirstRechargeRewardConfigRequest) (*activityv1.GetFirstRechargeRewardConfigResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
	config, err := s.svc.GetConfig(ctx)
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &activityv1.GetFirstRechargeRewardConfigResponse{Config: firstRechargeRewardConfigToProto(config)}, nil
}

func (s *AdminFirstRechargeRewardServer) UpdateFirstRechargeRewardConfig(ctx context.Context, req *activityv1.UpdateFirstRechargeRewardConfigRequest) (*activityv1.UpdateFirstRechargeRewardConfigResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
	tiers := make([]domain.Tier, 0, len(req.GetTiers()))
	for _, tier := range req.GetTiers() {
		tiers = append(tiers, domain.Tier{
			TierID:          tier.GetTierId(),
			TierCode:        tier.GetTierCode(),
			TierName:        tier.GetTierName(),
			MinCoinAmount:   tier.GetMinCoinAmount(),
			MaxCoinAmount:   tier.GetMaxCoinAmount(),
			ResourceGroupID: tier.GetResourceGroupId(),
			Status:          tier.GetStatus(),
			SortOrder:       tier.GetSortOrder(),
			USDMinorAmount:  tier.GetUsdMinorAmount(),
			GoogleProductID: tier.GetGoogleProductId(),
			DiscountPercent: tier.GetDiscountPercent(),
		})
	}
	config, err := s.svc.UpdateConfig(ctx, domain.Config{
		Enabled:          req.GetEnabled(),
		Tiers:            tiers,
		UpdatedByAdminID: req.GetOperatorAdminId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &activityv1.UpdateFirstRechargeRewardConfigResponse{Config: firstRechargeRewardConfigToProto(config)}, nil
}

func (s *AdminFirstRechargeRewardServer) ListFirstRechargeRewardClaims(ctx context.Context, req *activityv1.ListFirstRechargeRewardClaimsRequest) (*activityv1.ListFirstRechargeRewardClaimsResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
	claims, total, err := s.svc.ListClaims(ctx, domain.ClaimQuery{
		Status:   req.GetStatus(),
		UserID:   req.GetUserId(),
		Page:     req.GetPage(),
		PageSize: req.GetPageSize(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &activityv1.ListFirstRechargeRewardClaimsResponse{Claims: make([]*activityv1.FirstRechargeRewardClaim, 0, len(claims)), Total: total}
	for _, claim := range claims {
		resp.Claims = append(resp.Claims, firstRechargeRewardClaimToProto(claim))
	}
	return resp, nil
}

func firstRechargeRewardStatusToProto(status domain.StatusResult) *activityv1.FirstRechargeRewardStatus {
	resp := &activityv1.FirstRechargeRewardStatus{
		Enabled:      status.Enabled,
		Tiers:        make([]*activityv1.FirstRechargeRewardTier, 0, len(status.Tiers)),
		Rewarded:     status.Rewarded,
		Claim:        firstRechargeRewardClaimToProto(status.Claim),
		Claims:       make([]*activityv1.FirstRechargeRewardClaim, 0, len(status.Claims)),
		ServerTimeMs: status.ServerTimeMS,
	}
	for _, tier := range status.Tiers {
		resp.Tiers = append(resp.Tiers, firstRechargeRewardTierToProto(tier))
	}
	for _, claim := range status.Claims {
		resp.Claims = append(resp.Claims, firstRechargeRewardClaimToProto(claim))
	}
	return resp
}

func firstRechargeRewardConfigToProto(config domain.Config) *activityv1.FirstRechargeRewardConfig {
	resp := &activityv1.FirstRechargeRewardConfig{
		AppCode:          config.AppCode,
		Enabled:          config.Enabled,
		Tiers:            make([]*activityv1.FirstRechargeRewardTier, 0, len(config.Tiers)),
		UpdatedByAdminId: config.UpdatedByAdminID,
		CreatedAtMs:      config.CreatedAtMS,
		UpdatedAtMs:      config.UpdatedAtMS,
	}
	for _, tier := range config.Tiers {
		resp.Tiers = append(resp.Tiers, firstRechargeRewardTierToProto(tier))
	}
	return resp
}

func firstRechargeRewardTierToProto(tier domain.Tier) *activityv1.FirstRechargeRewardTier {
	return &activityv1.FirstRechargeRewardTier{
		TierId:          tier.TierID,
		TierCode:        tier.TierCode,
		TierName:        tier.TierName,
		MinCoinAmount:   tier.MinCoinAmount,
		MaxCoinAmount:   tier.MaxCoinAmount,
		ResourceGroupId: tier.ResourceGroupID,
		Status:          tier.Status,
		SortOrder:       tier.SortOrder,
		CreatedAtMs:     tier.CreatedAtMS,
		UpdatedAtMs:     tier.UpdatedAtMS,
		UsdMinorAmount:  tier.USDMinorAmount,
		GoogleProductId: tier.GoogleProductID,
		DiscountPercent: tier.DiscountPercent,
	}
}

func firstRechargeRewardClaimToProto(claim domain.Claim) *activityv1.FirstRechargeRewardClaim {
	if claim.ClaimID == "" {
		return nil
	}
	return &activityv1.FirstRechargeRewardClaim{
		ClaimId:            claim.ClaimID,
		EventId:            claim.EventID,
		TransactionId:      claim.TransactionID,
		CommandId:          claim.CommandID,
		UserId:             claim.UserID,
		TierId:             claim.TierID,
		TierCode:           claim.TierCode,
		ResourceGroupId:    claim.ResourceGroupID,
		RechargeCoinAmount: claim.RechargeCoinAmount,
		RechargeSequence:   claim.RechargeSequence,
		RechargeType:       claim.RechargeType,
		Status:             claim.Status,
		WalletCommandId:    claim.WalletCommandID,
		WalletGrantId:      claim.WalletGrantID,
		FailureReason:      claim.FailureReason,
		RechargedAtMs:      claim.RechargedAtMS,
		GrantedAtMs:        claim.GrantedAtMS,
		CreatedAtMs:        claim.CreatedAtMS,
		UpdatedAtMs:        claim.UpdatedAtMS,
		TierUsdMinorAmount: claim.TierUSDMinorAmount,
		GoogleProductId:    claim.GoogleProductID,
		RechargeUsdMinor:   claim.RechargeUSDMinor,
	}
}
