package activityapi

import (
	"net/http"
	"strings"

	activityv1 "hyapp.local/api/proto/activity/v1"
	"hyapp/services/gateway-service/internal/auth"
	"hyapp/services/gateway-service/internal/transport/http/httpkit"
)

type levelOverviewData struct {
	Tracks       []levelTrackOverviewData `json:"tracks"`
	ServerTimeMS int64                    `json:"server_time_ms"`
}

type levelTrackOverviewData struct {
	Track                        string `json:"track"`
	Name                         string `json:"name"`
	Level                        int32  `json:"level"`
	TierID                       int64  `json:"tier_id"`
	TotalValue                   int64  `json:"total_value"`
	CurrentLevelRequiredValue    int64  `json:"current_level_required_value"`
	NextLevel                    int32  `json:"next_level"`
	NextLevelRequiredValue       int64  `json:"next_level_required_value"`
	DisplayAvatarFrameResourceID int64  `json:"display_avatar_frame_resource_id"`
	DisplayBadgeResourceID       int64  `json:"display_badge_resource_id"`
	DisplayBadgeSourceLevel      int32  `json:"display_badge_source_level"`
	RewardPendingCount           int64  `json:"reward_pending_count"`
	SortOrder                    int32  `json:"sort_order"`
}

type levelTrackDetailData struct {
	Overview     levelTrackOverviewData `json:"overview"`
	Rules        []levelRuleData        `json:"rules"`
	Tiers        []levelTierData        `json:"tiers"`
	ServerTimeMS int64                  `json:"server_time_ms"`
}

type levelRuleData struct {
	Track                 string `json:"track"`
	Level                 int32  `json:"level"`
	RequiredValue         int64  `json:"required_value"`
	Name                  string `json:"name"`
	Status                string `json:"status"`
	RewardResourceGroupID int64  `json:"reward_resource_group_id"`
	SortOrder             int32  `json:"sort_order"`
	DisplayConfigJSON     string `json:"display_config_json"`
	CreatedByAdminID      int64  `json:"created_by_admin_id"`
	UpdatedByAdminID      int64  `json:"updated_by_admin_id"`
	CreatedAtMS           int64  `json:"created_at_ms"`
	UpdatedAtMS           int64  `json:"updated_at_ms"`
}

type levelTierData struct {
	TierID                       int64  `json:"tier_id"`
	Track                        string `json:"track"`
	MinLevel                     int32  `json:"min_level"`
	MaxLevel                     int32  `json:"max_level"`
	Name                         string `json:"name"`
	DisplayAvatarFrameResourceID int64  `json:"display_avatar_frame_resource_id"`
	DisplayBadgeResourceID       int64  `json:"display_badge_resource_id"`
	RewardResourceGroupID        int64  `json:"reward_resource_group_id"`
	Status                       string `json:"status"`
	DisplayConfigJSON            string `json:"display_config_json"`
	CreatedByAdminID             int64  `json:"created_by_admin_id"`
	UpdatedByAdminID             int64  `json:"updated_by_admin_id"`
	CreatedAtMS                  int64  `json:"created_at_ms"`
	UpdatedAtMS                  int64  `json:"updated_at_ms"`
}

type levelRewardData struct {
	RewardJobID      string `json:"reward_job_id"`
	UserID           int64  `json:"user_id"`
	Track            string `json:"track"`
	RewardSourceType string `json:"reward_source_type"`
	RewardSourceID   string `json:"reward_source_id"`
	ResourceGroupID  int64  `json:"resource_group_id"`
	WalletCommandID  string `json:"wallet_command_id"`
	WalletGrantID    string `json:"wallet_grant_id"`
	Status           string `json:"status"`
	AttemptCount     int32  `json:"attempt_count"`
	FailureReason    string `json:"failure_reason"`
	CreatedAtMS      int64  `json:"created_at_ms"`
	UpdatedAtMS      int64  `json:"updated_at_ms"`
}

func (h *Handler) getMyLevelOverview(writer http.ResponseWriter, request *http.Request) {
	if h.growthLevelClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	resp, err := h.growthLevelClient.GetMyLevelOverview(request.Context(), &activityv1.GetMyLevelOverviewRequest{
		Meta:   httpkit.ActivityMeta(request),
		UserId: auth.UserIDFromContext(request.Context()),
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	tracks := make([]levelTrackOverviewData, 0, len(resp.GetTracks()))
	for _, item := range resp.GetTracks() {
		tracks = append(tracks, levelTrackOverviewFromProto(item))
	}
	httpkit.WriteOK(writer, request, levelOverviewData{Tracks: tracks, ServerTimeMS: resp.GetServerTimeMs()})
}

func (h *Handler) getLevelTrack(writer http.ResponseWriter, request *http.Request) {
	if h.growthLevelClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	track := strings.TrimSpace(request.PathValue("track"))
	if track == "" {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
		return
	}
	resp, err := h.growthLevelClient.GetLevelTrack(request.Context(), &activityv1.GetLevelTrackRequest{
		Meta:   httpkit.ActivityMeta(request),
		UserId: auth.UserIDFromContext(request.Context()),
		Track:  track,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	rules := make([]levelRuleData, 0, len(resp.GetRules()))
	for _, rule := range resp.GetRules() {
		rules = append(rules, levelRuleFromProto(rule))
	}
	tiers := make([]levelTierData, 0, len(resp.GetTiers()))
	for _, tier := range resp.GetTiers() {
		tiers = append(tiers, levelTierFromProto(tier))
	}
	httpkit.WriteOK(writer, request, levelTrackDetailData{
		Overview:     levelTrackOverviewFromProto(resp.GetOverview()),
		Rules:        rules,
		Tiers:        tiers,
		ServerTimeMS: resp.GetServerTimeMs(),
	})
}

func (h *Handler) listLevelRewards(writer http.ResponseWriter, request *http.Request) {
	if h.growthLevelClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	page, ok := httpkit.PositiveInt32Query(request, "page", 1)
	if !ok {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
		return
	}
	pageSize, ok := httpkit.PositiveInt32Query(request, "page_size", 20)
	if !ok {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
		return
	}
	resp, err := h.growthLevelClient.ListLevelRewards(request.Context(), &activityv1.ListLevelRewardsRequest{
		Meta:     httpkit.ActivityMeta(request),
		UserId:   auth.UserIDFromContext(request.Context()),
		Track:    strings.TrimSpace(request.URL.Query().Get("track")),
		Status:   strings.TrimSpace(request.URL.Query().Get("status")),
		Page:     page,
		PageSize: pageSize,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	rewards := make([]levelRewardData, 0, len(resp.GetRewards()))
	for _, reward := range resp.GetRewards() {
		rewards = append(rewards, levelRewardFromProto(reward))
	}
	httpkit.WriteOK(writer, request, map[string]any{
		"rewards":   rewards,
		"total":     resp.GetTotal(),
		"page":      page,
		"page_size": pageSize,
	})
}

func levelTrackOverviewFromProto(item *activityv1.LevelTrackOverview) levelTrackOverviewData {
	return levelTrackOverviewData{
		Track:                        item.GetTrack(),
		Name:                         item.GetName(),
		Level:                        item.GetLevel(),
		TierID:                       item.GetTierId(),
		TotalValue:                   item.GetTotalValue(),
		CurrentLevelRequiredValue:    item.GetCurrentLevelRequiredValue(),
		NextLevel:                    item.GetNextLevel(),
		NextLevelRequiredValue:       item.GetNextLevelRequiredValue(),
		DisplayAvatarFrameResourceID: item.GetDisplayAvatarFrameResourceId(),
		DisplayBadgeResourceID:       item.GetDisplayBadgeResourceId(),
		DisplayBadgeSourceLevel:      item.GetDisplayBadgeSourceLevel(),
		RewardPendingCount:           item.GetRewardPendingCount(),
		SortOrder:                    item.GetSortOrder(),
	}
}

func levelRuleFromProto(item *activityv1.LevelRule) levelRuleData {
	return levelRuleData{
		Track:                 item.GetTrack(),
		Level:                 item.GetLevel(),
		RequiredValue:         item.GetRequiredValue(),
		Name:                  item.GetName(),
		Status:                item.GetStatus(),
		RewardResourceGroupID: item.GetRewardResourceGroupId(),
		SortOrder:             item.GetSortOrder(),
		DisplayConfigJSON:     item.GetDisplayConfigJson(),
		CreatedByAdminID:      item.GetCreatedByAdminId(),
		UpdatedByAdminID:      item.GetUpdatedByAdminId(),
		CreatedAtMS:           item.GetCreatedAtMs(),
		UpdatedAtMS:           item.GetUpdatedAtMs(),
	}
}

func levelTierFromProto(item *activityv1.LevelTier) levelTierData {
	return levelTierData{
		TierID:                       item.GetTierId(),
		Track:                        item.GetTrack(),
		MinLevel:                     item.GetMinLevel(),
		MaxLevel:                     item.GetMaxLevel(),
		Name:                         item.GetName(),
		DisplayAvatarFrameResourceID: item.GetDisplayAvatarFrameResourceId(),
		DisplayBadgeResourceID:       item.GetDisplayBadgeResourceId(),
		RewardResourceGroupID:        item.GetRewardResourceGroupId(),
		Status:                       item.GetStatus(),
		DisplayConfigJSON:            item.GetDisplayConfigJson(),
		CreatedByAdminID:             item.GetCreatedByAdminId(),
		UpdatedByAdminID:             item.GetUpdatedByAdminId(),
		CreatedAtMS:                  item.GetCreatedAtMs(),
		UpdatedAtMS:                  item.GetUpdatedAtMs(),
	}
}

func levelRewardFromProto(item *activityv1.LevelRewardJob) levelRewardData {
	return levelRewardData{
		RewardJobID:      item.GetRewardJobId(),
		UserID:           item.GetUserId(),
		Track:            item.GetTrack(),
		RewardSourceType: item.GetRewardSourceType(),
		RewardSourceID:   item.GetRewardSourceId(),
		ResourceGroupID:  item.GetResourceGroupId(),
		WalletCommandID:  item.GetWalletCommandId(),
		WalletGrantID:    item.GetWalletGrantId(),
		Status:           item.GetStatus(),
		AttemptCount:     item.GetAttemptCount(),
		FailureReason:    item.GetFailureReason(),
		CreatedAtMS:      item.GetCreatedAtMs(),
		UpdatedAtMS:      item.GetUpdatedAtMs(),
	}
}
