package activityapi

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	activityv1 "hyapp.local/api/proto/activity/v1"
	walletv1 "hyapp.local/api/proto/wallet/v1"
	"hyapp/services/gateway-service/internal/client"
)

type levelGrowthClientStub struct {
	client.GrowthLevelClient
	trackResponse *activityv1.GetLevelTrackResponse
}

func (s *levelGrowthClientStub) GetLevelTrack(context.Context, *activityv1.GetLevelTrackRequest) (*activityv1.GetLevelTrackResponse, error) {
	return s.trackResponse, nil
}

type levelWalletClientStub struct {
	client.WalletClient
	resources          map[int64]*walletv1.Resource
	resourceGroups     map[int64]*walletv1.ResourceGroup
	resourceCallCounts map[int64]int
}

func (s *levelWalletClientStub) GetResource(_ context.Context, request *walletv1.GetResourceRequest) (*walletv1.GetResourceResponse, error) {
	s.resourceCallCounts[request.GetResourceId()]++
	return &walletv1.GetResourceResponse{Resource: s.resources[request.GetResourceId()]}, nil
}

func (s *levelWalletClientStub) GetResourceGroup(_ context.Context, request *walletv1.GetResourceGroupRequest) (*walletv1.GetResourceGroupResponse, error) {
	return &walletv1.GetResourceGroupResponse{Group: s.resourceGroups[request.GetGroupId()]}, nil
}

func TestGetLevelTrackEmbedsTierMaterialsAndDeduplicatesResources(t *testing.T) {
	badge := &walletv1.Resource{
		ResourceId:   407,
		ResourceCode: "Charm_Badge_LV10-19",
		ResourceType: "badge",
		Name:         "Charm Badge 10-19",
		Status:       "active",
		PreviewUrl:   "https://cdn.example/charm-badge.png",
	}
	frame := &walletv1.Resource{
		ResourceId:   440,
		ResourceCode: "Charm_Frame_LV10-19",
		ResourceType: "avatar_frame",
		Name:         "Charm Frame 10-19",
		Status:       "active",
		PreviewUrl:   "https://cdn.example/charm-frame.png",
	}
	reward := &walletv1.Resource{
		ResourceId:   900,
		ResourceCode: "level_reward_gift",
		ResourceType: "gift",
		Name:         "Level Reward Gift",
		Status:       "active",
		PreviewUrl:   "https://cdn.example/level-gift.png",
	}
	wallet := &levelWalletClientStub{
		resources: map[int64]*walletv1.Resource{407: badge, 440: frame},
		resourceGroups: map[int64]*walletv1.ResourceGroup{77: {
			GroupId:   77,
			GroupCode: "charm_level_reward",
			Name:      "Charm Level Reward",
			Status:    "active",
			Items: []*walletv1.ResourceGroupItem{{
				GroupItemId: 1,
				ItemType:    "resource",
				ResourceId:  900,
				Resource:    reward,
				Quantity:    1,
			}},
		}},
		resourceCallCounts: map[int64]int{},
	}
	growth := &levelGrowthClientStub{trackResponse: &activityv1.GetLevelTrackResponse{
		Overview: &activityv1.LevelTrackOverview{
			Track:                        "charm",
			Level:                        12,
			DisplayAvatarFrameResourceId: 440,
			DisplayBadgeResourceId:       407,
		},
		Rules: []*activityv1.LevelRule{{Track: "charm", Level: 10, RewardResourceGroupId: 77}},
		Tiers: []*activityv1.LevelTier{{
			TierId:                       2,
			Track:                        "charm",
			MinLevel:                     10,
			MaxLevel:                     19,
			DisplayAvatarFrameResourceId: 440,
			DisplayBadgeResourceId:       407,
			RewardResourceGroupId:        77,
			Status:                       "active",
		}},
	}}
	handler := New(Config{GrowthLevelClient: growth, WalletClient: wallet})
	request := httptest.NewRequest(http.MethodGet, "/api/v1/levels/tracks/charm", nil)
	request.SetPathValue("track", "charm")
	recorder := httptest.NewRecorder()

	handler.getLevelTrack(recorder, request)

	if recorder.Code != http.StatusOK {
		t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
	}
	var envelope struct {
		Data struct {
			Overview struct {
				DisplayBadgeResource struct {
					PreviewURL string `json:"preview_url"`
				} `json:"display_badge_resource"`
			} `json:"overview"`
			Tiers []struct {
				DisplayAvatarFrameResource struct {
					PreviewURL string `json:"preview_url"`
				} `json:"display_avatar_frame_resource"`
				RewardResourceGroup struct {
					Items []struct {
						Resource struct {
							PreviewURL string `json:"preview_url"`
						} `json:"resource"`
					} `json:"items"`
				} `json:"reward_resource_group"`
			} `json:"tiers"`
		} `json:"data"`
	}
	if err := json.NewDecoder(recorder.Body).Decode(&envelope); err != nil {
		t.Fatalf("decode response: %v", err)
	}
	if envelope.Data.Overview.DisplayBadgeResource.PreviewURL != badge.GetPreviewUrl() {
		t.Fatalf("overview badge material missing: %+v", envelope.Data.Overview)
	}
	if len(envelope.Data.Tiers) != 1 || envelope.Data.Tiers[0].DisplayAvatarFrameResource.PreviewURL != frame.GetPreviewUrl() {
		t.Fatalf("tier frame material missing: %+v", envelope.Data.Tiers)
	}
	if envelope.Data.Tiers[0].RewardResourceGroup.Items[0].Resource.PreviewURL != reward.GetPreviewUrl() {
		t.Fatalf("tier reward material missing: %+v", envelope.Data.Tiers[0].RewardResourceGroup)
	}
	// Overview 与 tier 会引用同一素材；请求内按 ID 去重，避免每次打开等级页重复打 wallet-service。
	if wallet.resourceCallCounts[407] != 1 || wallet.resourceCallCounts[440] != 1 {
		t.Fatalf("resource lookup was not deduplicated: %+v", wallet.resourceCallCounts)
	}
}
