package appapi

import (
	"net/http"
	"strconv"
	"strings"
	"time"

	"hyapp/pkg/appcode"
	"hyapp/services/gateway-service/internal/appconfig"
	"hyapp/services/gateway-service/internal/auth"
	"hyapp/services/gateway-service/internal/transport/http/httpkit"

	userv1 "hyapp.local/api/proto/user/v1"
)

type appBootstrapBottomTab struct {
	Key     string `json:"key"`
	Title   string `json:"title"`
	Enabled bool   `json:"enabled"`
}

type appBootstrapResponse struct {
	AppCode        string                  `json:"app_code"`
	ServerTimeMS   int64                   `json:"server_time_ms"`
	ForceUpgrade   bool                    `json:"force_upgrade"`
	Maintenance    bool                    `json:"maintenance"`
	MinimumVersion string                  `json:"minimum_version"`
	LatestVersion  string                  `json:"latest_version"`
	FeatureFlags   map[string]bool         `json:"feature_flags"`
	BottomTabs     []appBootstrapBottomTab `json:"bottom_tabs"`
	ConfigVersions map[string]string       `json:"config_versions"`
}

type appVersionResponse struct {
	AppCode            string `json:"app_code"`
	Platform           string `json:"platform"`
	Version            string `json:"version"`
	BuildNumber        int64  `json:"build_number"`
	ForceUpdate        bool   `json:"force_update"`
	DownloadURL        string `json:"download_url"`
	Description        string `json:"description"`
	HasUpdate          bool   `json:"has_update"`
	CurrentBuildNumber int64  `json:"current_build_number"`
	UpdatedAtMs        int64  `json:"updated_at_ms"`
	ServerTimeMs       int64  `json:"server_time_ms"`
}

// getAppBootstrap 返回 App 启动状态机需要的轻量配置摘要。
// bootstrap 只下发版本、开关和配置版本号，不返回 banner、礼物或资源大列表。
func (h *Handler) getAppBootstrap(writer http.ResponseWriter, request *http.Request) {
	httpkit.WriteOK(writer, request, appBootstrapResponse{
		AppCode:        appcode.FromContext(request.Context()),
		ServerTimeMS:   time.Now().UnixMilli(),
		ForceUpgrade:   false,
		Maintenance:    false,
		MinimumVersion: "1.0.0",
		LatestVersion:  "1.0.0",
		FeatureFlags: map[string]bool{
			"wallet_recharge":  true,
			"wallet_withdraw":  true,
			"diamond_exchange": false,
			"message_tab":      true,
			"host_center":      true,
			"room_create":      true,
		},
		BottomTabs: []appBootstrapBottomTab{
			{Key: "rooms", Title: "房间", Enabled: true},
			{Key: "messages", Title: "消息", Enabled: true},
			{Key: "me", Title: "我的", Enabled: true},
		},
		ConfigVersions: map[string]string{
			"countries":    "v1",
			"banners":      "v1",
			"h5_links":     "v1",
			"explore_tabs": "v1",
			"popups":       "v1",
			"resources":    "v1",
			"gifts":        "v1",
		},
	})
}

// listH5Links 返回后台 APP配置/H5配置 中维护的 H5 入口地址。
func (h *Handler) listH5Links(writer http.ResponseWriter, request *http.Request) {
	if h.appConfigReader == nil {
		// H5 地址来自后台配置表；未注入 reader 时不能返回空假数据。
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	items, err := h.appConfigReader.ListH5Links(request.Context(), appconfig.H5LinkQuery{
		AppCode: appcode.FromContext(request.Context()),
		UserID:  auth.UserIDFromContext(request.Context()),
	})
	if err != nil {
		// 配置读取失败属于服务端依赖异常，客户端只需要根据 request_id 排查。
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	httpkit.WriteOK(writer, request, map[string]any{"items": items, "total": len(items)})
}

// listExploreTabs 返回后台 APP配置/Explore配置 中启用的 H5 tab。
func (h *Handler) listExploreTabs(writer http.ResponseWriter, request *http.Request) {
	if h.appConfigReader == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	items, err := h.appConfigReader.ListExploreTabs(request.Context(), appcode.FromContext(request.Context()))
	if err != nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	httpkit.WriteOK(writer, request, map[string]any{"items": items, "total": len(items)})
}

// listAppBanners 返回后台 APP配置/BANNER配置 中维护的指定显示范围 banner。
func (h *Handler) listAppBanners(writer http.ResponseWriter, request *http.Request) {
	if h.appConfigReader == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	displayScope := appconfig.NormalizeBannerDisplayScope(firstQuery(request, "display_scope", "displayScope"))
	if displayScope == "" {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "display_scope is invalid")
		return
	}

	query := appconfig.BannerQuery{
		AppCode:      appcode.FromContext(request.Context()),
		DisplayScope: displayScope,
		Platform:     httpkit.FirstQueryOrHeader(request, "platform", "X-App-Platform", "X-Platform"),
	}
	if !h.applyAuthenticatedBannerAudience(writer, request, &query) {
		return
	}

	items, err := h.appConfigReader.ListBanners(request.Context(), query)
	if err != nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	httpkit.WriteOK(writer, request, map[string]any{"items": items, "total": len(items)})
}

func (h *Handler) applyAuthenticatedBannerAudience(writer http.ResponseWriter, request *http.Request, query *appconfig.BannerQuery) bool {
	viewerUserID := auth.UserIDFromContext(request.Context())
	if viewerUserID == 0 {
		// banner 是公开接口，但未登录请求不能用 region_id/country 伪装区域身份；空区域只会命中全局 banner。
		return true
	}
	if h.userProfileClient == nil {
		// 登录态区域必须以 user-service 的用户事实为准，缺少依赖时不能退回客户端传参。
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return false
	}

	resp, err := h.userProfileClient.GetUser(request.Context(), &userv1.GetUserRequest{
		Meta:   httpkit.UserMeta(request, ""),
		UserId: viewerUserID,
	})
	if err != nil {
		// user-service 查询失败时返回上游错误，避免用客户端 region_id/country 打开错误区域的 banner。
		httpkit.WriteRPCError(writer, request, err)
		return false
	}
	user := resp.GetUser()
	if user == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return false
	}
	if user.GetAppCode() != "" && appcode.Normalize(user.GetAppCode()) != query.AppCode {
		// token 所属租户和用户资料租户不一致时拒绝返回区域配置，防止跨 App 读取 banner 策略。
		httpkit.WriteError(writer, request, http.StatusForbidden, httpkit.CodePermissionDenied, "permission denied")
		return false
	}
	if user.GetContentBlacklisted() {
		// Banner 仍保留公开匿名访问兼容；一旦请求携带有效登录态，user-service 的黑名单事实优先并直接返回空列表。
		httpkit.WriteOK(writer, request, map[string]any{"items": []appconfig.Banner{}, "total": 0})
		return false
	}

	// 已登录用户的区域由后端用户资料覆盖；客户端保留 region_id/country 只做老版本参数兼容，不参与裁决。
	query.RegionID = user.GetRegionId()
	query.Country = strings.TrimSpace(user.GetCountry())
	return true
}

// listSplashScreens 返回后台 APP配置/开屏配置 中当前可见的开屏列表；客户端按列表顺序取最高优先级配置展示。
func (h *Handler) listSplashScreens(writer http.ResponseWriter, request *http.Request) {
	if h.appConfigReader == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	items, err := h.appConfigReader.ListSplashScreens(request.Context(), appconfig.SplashScreenQuery{
		AppCode:  appcode.FromContext(request.Context()),
		Platform: httpkit.FirstQueryOrHeader(request, "platform", "X-App-Platform", "X-Platform"),
		RegionID: optionalInt64Query(request, "region_id"),
		Country:  httpkit.FirstQueryOrHeader(request, "country", "X-Country-Code", "X-App-Country"),
	})
	if err != nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	httpkit.WriteOK(writer, request, map[string]any{"items": items, "total": len(items)})
}

// listPopups 返回后台 APP配置/弹窗配置 中当前可见的弹窗列表；客户端按 display_period_days 做本地展示频控。
func (h *Handler) listPopups(writer http.ResponseWriter, request *http.Request) {
	if h.appConfigReader == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	items, err := h.appConfigReader.ListPopups(request.Context(), appconfig.PopupQuery{
		AppCode: appcode.FromContext(request.Context()),
	})
	if err != nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	httpkit.WriteOK(writer, request, map[string]any{"items": items, "total": len(items)})
}

// getAppVersion 返回当前平台最新版本；App 用 build_number 判定是否需要提示升级。
func (h *Handler) getAppVersion(writer http.ResponseWriter, request *http.Request) {
	if h.appConfigReader == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	platform := normalizeAppPlatform(httpkit.FirstQueryOrHeader(request, "platform", "X-App-Platform", "X-Platform"))
	if platform != "android" && platform != "ios" {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "platform is invalid")
		return
	}
	currentBuildNumber := optionalInt64QueryOrHeader(request, "build_number", "X-App-Build-Number", "X-Build-Number")
	item, err := h.appConfigReader.LatestVersion(request.Context(), appconfig.VersionQuery{
		AppCode:            appcode.FromContext(request.Context()),
		Platform:           platform,
		CurrentBuildNumber: currentBuildNumber,
	})
	if err != nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	httpkit.WriteOK(writer, request, appVersionResponse{
		AppCode:            item.AppCode,
		Platform:           platform,
		Version:            item.Version,
		BuildNumber:        item.BuildNumber,
		ForceUpdate:        item.ForceUpdate && item.BuildNumber > currentBuildNumber,
		DownloadURL:        item.DownloadURL,
		Description:        item.Description,
		HasUpdate:          item.BuildNumber > currentBuildNumber,
		CurrentBuildNumber: currentBuildNumber,
		UpdatedAtMs:        item.UpdatedAtMs,
		ServerTimeMs:       time.Now().UTC().UnixMilli(),
	})
}

func optionalInt64QueryOrHeader(request *http.Request, queryKey string, headerNames ...string) int64 {
	value := httpkit.FirstQueryOrHeader(request, queryKey, headerNames...)
	if value == "" {
		return 0
	}
	parsed, err := strconv.ParseInt(value, 10, 64)
	if err != nil || parsed < 0 {
		return 0
	}
	return parsed
}

func optionalInt64Query(request *http.Request, key string) int64 {
	value := strings.TrimSpace(request.URL.Query().Get(key))
	if value == "" {
		return 0
	}
	parsed, err := strconv.ParseInt(value, 10, 64)
	if err != nil || parsed < 0 {
		return 0
	}
	return parsed
}

func firstQuery(request *http.Request, keys ...string) string {
	values := request.URL.Query()
	for _, key := range keys {
		if value := strings.TrimSpace(values.Get(key)); value != "" {
			return value
		}
	}
	return ""
}

func normalizeAppPlatform(value string) string {
	return strings.ToLower(strings.TrimSpace(value))
}
