package grpc

import (
	"context"

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

// CumulativeRechargeRewardServer 暴露 App 累充奖励查询和内部充值事实消费入口。
type CumulativeRechargeRewardServer struct {
	activityv1.UnimplementedCumulativeRechargeRewardServiceServer

	svc *service.Service
}

func NewCumulativeRechargeRewardServer(svc *service.Service) *CumulativeRechargeRewardServer {
	return &CumulativeRechargeRewardServer{svc: svc}
}

func (s *CumulativeRechargeRewardServer) GetCumulativeRechargeRewardStatus(ctx context.Context, req *activityv1.GetCumulativeRechargeRewardStatusRequest) (*activityv1.GetCumulativeRechargeRewardStatusResponse, 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.GetCumulativeRechargeRewardStatusResponse{Status: cumulativeRechargeRewardStatusToProto(status)}, nil
}

func (s *CumulativeRechargeRewardServer) ConsumeCumulativeRechargeReward(ctx context.Context, req *activityv1.ConsumeCumulativeRechargeRewardRequest) (*activityv1.ConsumeCumulativeRechargeRewardResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
	grants, 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(),
		QualifyingUSDMinor: req.GetQualifyingUsdMinor(),
		PayloadJSON:        req.GetPayloadJson(),
		OccurredAtMS:       req.GetOccurredAtMs(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &activityv1.ConsumeCumulativeRechargeRewardResponse{
		Grants:   make([]*activityv1.CumulativeRechargeRewardGrant, 0, len(grants)),
		Consumed: consumed,
		Reason:   reason,
	}
	for _, grant := range grants {
		resp.Grants = append(resp.Grants, cumulativeRechargeRewardGrantToProto(grant))
	}
	return resp, nil
}

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

	svc *service.Service
}

func NewAdminCumulativeRechargeRewardServer(svc *service.Service) *AdminCumulativeRechargeRewardServer {
	return &AdminCumulativeRechargeRewardServer{svc: svc}
}

func (s *AdminCumulativeRechargeRewardServer) GetCumulativeRechargeRewardConfig(ctx context.Context, req *activityv1.GetCumulativeRechargeRewardConfigRequest) (*activityv1.GetCumulativeRechargeRewardConfigResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
	config, err := s.svc.GetConfig(ctx)
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &activityv1.GetCumulativeRechargeRewardConfigResponse{Config: cumulativeRechargeRewardConfigToProto(config)}, nil
}

func (s *AdminCumulativeRechargeRewardServer) UpdateCumulativeRechargeRewardConfig(ctx context.Context, req *activityv1.UpdateCumulativeRechargeRewardConfigRequest) (*activityv1.UpdateCumulativeRechargeRewardConfigResponse, 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(),
			ThresholdUSDMinor: tier.GetThresholdUsdMinor(),
			ResourceGroupID:   tier.GetResourceGroupId(),
			Status:            tier.GetStatus(),
			SortOrder:         tier.GetSortOrder(),
		})
	}
	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.UpdateCumulativeRechargeRewardConfigResponse{Config: cumulativeRechargeRewardConfigToProto(config)}, nil
}

func (s *AdminCumulativeRechargeRewardServer) ListCumulativeRechargeRewardGrants(ctx context.Context, req *activityv1.ListCumulativeRechargeRewardGrantsRequest) (*activityv1.ListCumulativeRechargeRewardGrantsResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
	grants, total, err := s.svc.ListGrants(ctx, domain.GrantQuery{
		Status:   req.GetStatus(),
		UserID:   req.GetUserId(),
		CycleKey: req.GetCycleKey(),
		Page:     req.GetPage(),
		PageSize: req.GetPageSize(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &activityv1.ListCumulativeRechargeRewardGrantsResponse{Grants: make([]*activityv1.CumulativeRechargeRewardGrant, 0, len(grants)), Total: total}
	for _, grant := range grants {
		resp.Grants = append(resp.Grants, cumulativeRechargeRewardGrantToProto(grant))
	}
	return resp, nil
}

func cumulativeRechargeRewardStatusToProto(status domain.StatusResult) *activityv1.CumulativeRechargeRewardStatus {
	resp := &activityv1.CumulativeRechargeRewardStatus{
		Config:        cumulativeRechargeRewardConfigToProto(status.Config),
		Progress:      cumulativeRechargeRewardProgressToProto(status.Progress),
		Grants:        make([]*activityv1.CumulativeRechargeRewardGrant, 0, len(status.Grants)),
		CycleKey:      status.Cycle.Key,
		PeriodStartMs: status.Cycle.StartMS,
		PeriodEndMs:   status.Cycle.EndMS,
		ServerTimeMs:  status.ServerTimeMS,
	}
	for _, grant := range status.Grants {
		resp.Grants = append(resp.Grants, cumulativeRechargeRewardGrantToProto(grant))
	}
	return resp
}

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

func cumulativeRechargeRewardTierToProto(tier domain.Tier) *activityv1.CumulativeRechargeRewardTier {
	return &activityv1.CumulativeRechargeRewardTier{
		TierId:            tier.TierID,
		TierCode:          tier.TierCode,
		TierName:          tier.TierName,
		ThresholdUsdMinor: tier.ThresholdUSDMinor,
		ResourceGroupId:   tier.ResourceGroupID,
		Status:            tier.Status,
		SortOrder:         tier.SortOrder,
		CreatedAtMs:       tier.CreatedAtMS,
		UpdatedAtMs:       tier.UpdatedAtMS,
	}
}

func cumulativeRechargeRewardProgressToProto(progress domain.Progress) *activityv1.CumulativeRechargeRewardProgress {
	return &activityv1.CumulativeRechargeRewardProgress{
		AppCode:            progress.AppCode,
		CycleKey:           progress.CycleKey,
		UserId:             progress.UserID,
		TotalUsdMinor:      progress.TotalUSDMinor,
		TotalCoinAmount:    progress.TotalCoinAmount,
		FirstRechargedAtMs: progress.FirstRechargedAtMS,
		LastRechargedAtMs:  progress.LastRechargedAtMS,
		UpdatedAtMs:        progress.UpdatedAtMS,
	}
}

func cumulativeRechargeRewardGrantToProto(grant domain.Grant) *activityv1.CumulativeRechargeRewardGrant {
	if grant.GrantID == "" {
		return nil
	}
	return &activityv1.CumulativeRechargeRewardGrant{
		GrantId:            grant.GrantID,
		AppCode:            grant.AppCode,
		CycleKey:           grant.CycleKey,
		UserId:             grant.UserID,
		EventId:            grant.EventID,
		TransactionId:      grant.TransactionID,
		CommandId:          grant.CommandID,
		TierId:             grant.TierID,
		TierCode:           grant.TierCode,
		ThresholdUsdMinor:  grant.ThresholdUSDMinor,
		ResourceGroupId:    grant.ResourceGroupID,
		ReachedUsdMinor:    grant.ReachedUSDMinor,
		QualifyingUsdMinor: grant.QualifyingUSDMinor,
		RechargeCoinAmount: grant.RechargeCoinAmount,
		RechargeType:       grant.RechargeType,
		Status:             grant.Status,
		WalletCommandId:    grant.WalletCommandID,
		WalletGrantId:      grant.WalletGrantID,
		FailureReason:      grant.FailureReason,
		GrantedAtMs:        grant.GrantedAtMS,
		CreatedAtMs:        grant.CreatedAtMS,
		UpdatedAtMs:        grant.UpdatedAtMS,
	}
}
