package userapi

import (
	"context"
	"hyapp/services/gateway-service/internal/transport/http/httpkit"
	"net/http"
	"sync"
	"time"

	userv1 "hyapp.local/api/proto/user/v1"
	walletv1 "hyapp.local/api/proto/wallet/v1"
	"hyapp/pkg/appcode"
	"hyapp/pkg/xerr"
	"hyapp/services/gateway-service/internal/auth"
)

const overviewAggregationTimeout = 200 * time.Millisecond

type myOverviewData struct {
	Profile      userProfileData      `json:"profile"`
	ProfileStats overviewProfileStats `json:"profile_stats"`
	Wallet       overviewWalletData   `json:"wallet"`
	VIP          overviewVIPData      `json:"vip"`
	Roles        overviewRolesData    `json:"roles"`
	Entries      []overviewEntryData  `json:"entries"`
	ServerTimeMS int64                `json:"server_time_ms"`
}

type overviewWalletData struct {
	CoinAmount  int64 `json:"coin_amount"`
	UpdatedAtMS int64 `json:"updated_at_ms"`
	Unavailable bool  `json:"unavailable,omitempty"`
}

type overviewRolesData struct {
	IsHost                 bool   `json:"is_host"`
	IsAgency               bool   `json:"is_agency"`
	IsManager              bool   `json:"is_manager"`
	IsBD                   bool   `json:"is_bd"`
	IsBDLeader             bool   `json:"is_bd_leader"`
	IsCoinSeller           bool   `json:"is_coin_seller"`
	HostStatus             string `json:"host_status,omitempty"`
	AgencyID               int64  `json:"agency_id,omitempty"`
	BDID                   int64  `json:"bd_id,omitempty"`
	BDStatus               string `json:"bd_status,omitempty"`
	CoinSellerStatus       string `json:"coin_seller_status,omitempty"`
	PendingRoleInvitations int64  `json:"pending_role_invitations"`
	Unavailable            bool   `json:"unavailable,omitempty"`
}

type overviewProfileStats struct {
	VisitorsCount  int64 `json:"visitors_count"`
	FollowingCount int64 `json:"following_count"`
	FollowersCount int64 `json:"followers_count"`
	FriendsCount   int64 `json:"friends_count"`
	UpdatedAtMS    int64 `json:"updated_at_ms"`
	Unavailable    bool  `json:"unavailable,omitempty"`
}

type overviewEntryData struct {
	Key        string `json:"key"`
	Visible    bool   `json:"visible"`
	Enabled    bool   `json:"enabled"`
	Route      string `json:"route"`
	IconKey    string `json:"icon_key"`
	BadgeCount int64  `json:"badge_count"`
	Order      int32  `json:"order"`
}

type overviewVIPData struct {
	Level        int32                       `json:"level"`
	Name         string                      `json:"name"`
	Active       bool                        `json:"active"`
	StartedAtMS  int64                       `json:"started_at_ms"`
	ExpiresAtMS  int64                       `json:"expires_at_ms"`
	UserSettings overviewVIPUserSettingsData `json:"user_settings"`
	Unavailable  bool                        `json:"unavailable,omitempty"`
}

// overviewVIPUserSettingsData 只出现在当前用户的私有聚合接口。不能把这些 wallet
// 偏好塞进公共 userProfileData，否则查看他人资料和批量用户读取会泄露私有设置。
type overviewVIPUserSettingsData struct {
	AppCode                      string `json:"app_code"`
	UserID                       int64  `json:"user_id"`
	RoomEntryNoticeEnabled       bool   `json:"room_entry_notice_enabled"`
	OnlineGlobalNoticeEnabled    bool   `json:"online_global_notice_enabled"`
	HideProfileDataEnabled       bool   `json:"hide_profile_data_enabled"`
	AnonymousProfileVisitEnabled bool   `json:"anonymous_profile_visit_enabled"`
	LeaderboardInvisibleEnabled  bool   `json:"leaderboard_invisible_enabled"`
	UpdatedAtMS                  int64  `json:"updated_at_ms"`
}

// getMyOverview 聚合 App 我的页首屏摘要；gateway 只做 RPC 编排和入口显隐规则，不查数据库。
func (h *Handler) getMyOverview(writer http.ResponseWriter, request *http.Request) {
	if h.userProfileClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	ctx, cancel := context.WithTimeout(request.Context(), overviewAggregationTimeout)
	defer cancel()

	userID := auth.UserIDFromContext(request.Context())
	var wg sync.WaitGroup

	var profileResp *userv1.GetUserResponse
	var profileErr error
	wg.Go(func() {
		profileResp, profileErr = h.userProfileClient.GetUser(ctx, &userv1.GetUserRequest{
			Meta:   httpkit.UserMeta(request.WithContext(ctx), ""),
			UserId: userID,
		})
	})

	var walletResp *walletv1.GetWalletValueSummaryResponse
	var walletErr error
	wg.Go(func() {
		if h.walletClient == nil {
			walletErr = xerr.New(xerr.Unavailable, "wallet service is not configured")
			return
		}
		walletResp, walletErr = h.walletClient.GetWalletValueSummary(ctx, &walletv1.GetWalletValueSummaryRequest{
			RequestId: httpkit.RequestIDFromContext(request.Context()),
			UserId:    userID,
			AppCode:   appcode.FromContext(request.Context()),
		})
	})

	var vipResp *walletv1.GetMyVipResponse
	var vipErr error
	wg.Go(func() {
		if h.walletClient == nil {
			vipErr = xerr.New(xerr.Unavailable, "wallet service is not configured")
			return
		}
		vipResp, vipErr = h.walletClient.GetMyVip(ctx, &walletv1.GetMyVipRequest{
			RequestId: httpkit.RequestIDFromContext(request.Context()),
			UserId:    userID,
			AppCode:   appcode.FromContext(request.Context()),
		})
	})

	var roles overviewRolesData
	var rolesErr error
	wg.Go(func() {
		roles, rolesErr = h.getOverviewRoles(ctx, request, userID)
	})

	var statsResp *userv1.GetMyProfileStatsResponse
	var statsErr error
	wg.Go(func() {
		statsResp, statsErr = h.userProfileClient.GetMyProfileStats(ctx, &userv1.GetMyProfileStatsRequest{
			Meta:   httpkit.UserMeta(request.WithContext(ctx), ""),
			UserId: userID,
		})
	})

	wg.Wait()
	if profileErr != nil {
		httpkit.WriteRPCError(writer, request, profileErr)
		return
	}
	if profileResp.GetUser() == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	if rolesErr != nil {
		roles = overviewRolesData{Unavailable: true}
	}
	wallet := overviewWallet(walletResp, walletErr)
	vip := overviewVIP(vipResp, vipErr, appcode.FromContext(request.Context()), userID)
	profileStats := overviewStats(statsResp, statsErr)

	httpkit.WriteOK(writer, request, myOverviewData{
		Profile:      profileData(profileResp.GetUser(), 0),
		ProfileStats: profileStats,
		Wallet:       wallet,
		VIP:          vip,
		Roles:        roles,
		Entries:      overviewEntries(roles),
		ServerTimeMS: time.Now().UnixMilli(),
	})
}

func (h *Handler) getOverviewRoles(ctx context.Context, request *http.Request, userID int64) (overviewRolesData, error) {
	if h.userHostClient == nil {
		return overviewRolesData{}, xerr.New(xerr.Unavailable, "user host service is not configured")
	}

	resp, err := h.userHostClient.GetUserRoleSummary(ctx, &userv1.GetUserRoleSummaryRequest{
		Meta:   httpkit.UserMeta(request.WithContext(ctx), ""),
		UserId: userID,
	})
	if err != nil {
		return overviewRolesData{}, err
	}
	summary := resp.GetSummary()
	return overviewRolesData{
		IsHost:                 summary.GetIsHost(),
		IsAgency:               summary.GetIsAgency(),
		IsManager:              summary.GetIsManager(),
		IsBD:                   summary.GetIsBd(),
		IsBDLeader:             summary.GetIsBdLeader(),
		IsCoinSeller:           summary.GetIsCoinSeller(),
		HostStatus:             summary.GetHostStatus(),
		AgencyID:               summary.GetAgencyId(),
		BDID:                   summary.GetBdId(),
		BDStatus:               summary.GetBdStatus(),
		CoinSellerStatus:       summary.GetCoinSellerStatus(),
		PendingRoleInvitations: summary.GetPendingRoleInvitations(),
	}, nil
}

func overviewWallet(resp *walletv1.GetWalletValueSummaryResponse, err error) overviewWalletData {
	if err != nil {
		return overviewWalletData{Unavailable: true}
	}
	summary := resp.GetSummary()
	return overviewWalletData{
		CoinAmount:  summary.GetCoinAmount(),
		UpdatedAtMS: summary.GetUpdatedAtMs(),
	}
}

func overviewVIP(resp *walletv1.GetMyVipResponse, err error, appCode string, userID int64) overviewVIPData {
	settings := overviewVIPUserSettings(resp.GetState().GetUserSettings(), appCode, userID)
	if err != nil {
		// 聚合接口保持稳定 JSON shape，但 unavailable=true 明确表示本次默认值
		// 不是已确认的持久化事实；客户端不应在降级时覆盖本地最后一次成功状态。
		return overviewVIPData{UserSettings: settings, Unavailable: true}
	}
	vip := resp.GetVip()
	return overviewVIPData{
		Level:        vip.GetLevel(),
		Name:         vip.GetName(),
		Active:       vip.GetActive(),
		StartedAtMS:  vip.GetStartedAtMs(),
		ExpiresAtMS:  vip.GetExpiresAtMs(),
		UserSettings: settings,
	}
}

// overviewVIPUserSettings 复用当前 GetMyVip 回包，不增加 RPC。旧 wallet 实例缺少
// user_settings 时与 wallet owner 的缺行语义保持一致：通知开启，三项隐私能力关闭。
func overviewVIPUserSettings(settings *walletv1.VipUserSettings, appCode string, userID int64) overviewVIPUserSettingsData {
	result := overviewVIPUserSettingsData{
		AppCode: appCode, UserID: userID,
		RoomEntryNoticeEnabled: true, OnlineGlobalNoticeEnabled: true,
	}
	if settings == nil {
		return result
	}
	result.AppCode = settings.GetAppCode()
	if result.AppCode == "" {
		result.AppCode = appCode
	}
	result.UserID = settings.GetUserId()
	if result.UserID == 0 {
		result.UserID = userID
	}
	result.RoomEntryNoticeEnabled = settings.GetRoomEntryNoticeEnabled()
	result.OnlineGlobalNoticeEnabled = settings.GetOnlineGlobalNoticeEnabled()
	result.HideProfileDataEnabled = settings.GetHideProfileDataEnabled()
	result.AnonymousProfileVisitEnabled = settings.GetAnonymousProfileVisitEnabled()
	result.LeaderboardInvisibleEnabled = settings.GetLeaderboardInvisibleEnabled()
	result.UpdatedAtMS = settings.GetUpdatedAtMs()
	return result
}

func overviewStats(resp *userv1.GetMyProfileStatsResponse, err error) overviewProfileStats {
	if err != nil {
		return overviewProfileStats{Unavailable: true}
	}
	return overviewStatsFromProto(resp.GetStats())
}

func overviewStatsFromProto(stats *userv1.UserProfileStats) overviewProfileStats {
	return overviewProfileStats{
		VisitorsCount:  stats.GetVisitorsCount(),
		FollowingCount: stats.GetFollowingCount(),
		FollowersCount: stats.GetFollowersCount(),
		FriendsCount:   stats.GetFriendsCount(),
		UpdatedAtMS:    stats.GetUpdatedAtMs(),
	}
}

func overviewEntries(roles overviewRolesData) []overviewEntryData {
	return []overviewEntryData{
		{Key: "store", Visible: true, Enabled: true, Route: "/store", IconKey: "store", Order: 10},
		{Key: "bag", Visible: true, Enabled: true, Route: "/bag", IconKey: "bag", Order: 20},
		{Key: "level", Visible: true, Enabled: true, Route: "/level", IconKey: "level", Order: 30},
		{Key: "task", Visible: true, Enabled: true, Route: "/task", IconKey: "task", Order: 40},
		{Key: "apply_host", Visible: !roles.IsHost, Enabled: true, Route: "/host/apply", IconKey: "host_apply", Order: 50},
		{Key: "host_center", Visible: roles.IsHost, Enabled: roles.IsHost, Route: "/host", IconKey: "host_center", Order: 60},
		{Key: "agency_center", Visible: roles.IsAgency, Enabled: roles.IsAgency, Route: "/agency", IconKey: "agency", Order: 70},
		{Key: "manager_center", Visible: roles.IsManager, Enabled: roles.IsManager, Route: "/manager-center", IconKey: "manager_center", Order: 80},
		{Key: "bd_center", Visible: roles.IsBD, Enabled: roles.IsBD, Route: "/bd", IconKey: "bd", Order: 90},
		// BD Leader 和超管在 H5 里共用 superadmin-center 页面；入口 key 也统一成 superadmin_center，避免客户端再出现两个中心口径。
		{Key: "superadmin_center", Visible: roles.IsBDLeader, Enabled: roles.IsBDLeader, Route: "/superadmin-center", IconKey: "bd_leader", Order: 100},
		{Key: "coin_seller_center", Visible: roles.IsCoinSeller, Enabled: roles.IsCoinSeller, Route: "/coin-seller", IconKey: "coin_seller", Order: 110},
		{Key: "settings", Visible: true, Enabled: true, Route: "/settings", IconKey: "settings", Order: 120},
		{Key: "language", Visible: true, Enabled: true, Route: "/language", IconKey: "language", Order: 130},
	}
}
