package appapi

import (
	"net/http"
	"strconv"

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

type appHeartbeatData struct {
	Accepted      bool   `json:"accepted"`
	HeartbeatAtMS int64  `json:"heartbeat_at_ms"`
	ServerTimeMS  int64  `json:"server_time_ms"`
	AccessToken   string `json:"access_token,omitempty"`
	TokenType     string `json:"token_type,omitempty"`
	ExpiresInSec  int64  `json:"expires_in_sec,omitempty"`
}

const (
	renewedAccessTokenHeader = "X-Hyapp-Access-Token"
	renewedTokenTypeHeader   = "X-Hyapp-Token-Type"
	renewedExpiresInHeader   = "X-Hyapp-Expires-In"
)

// appHeartbeat 刷新当前登录 App 会话，不写房间 presence，也不改变麦位在线状态。
func (h *Handler) appHeartbeat(writer http.ResponseWriter, request *http.Request) {
	if h.userAuthClient == nil {
		// App 心跳必须落 user-service session；未注入时不能返回假在线。
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	sessionID := auth.SessionIDFromContext(request.Context())
	resp, err := h.userAuthClient.AppHeartbeat(request.Context(), &userv1.AppHeartbeatRequest{
		Meta:      httpkit.UserMeta(request, httpkit.FirstHeader(request, "X-Device-ID", "X-HY-Device-ID")),
		UserId:    auth.UserIDFromContext(request.Context()),
		SessionId: sessionID,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	token := resp.GetToken()
	if token.GetAccessToken() != "" {
		// HTTP header 让 H5 通用请求层无感更新 token；JSON 字段保留给原生端显式消费。
		writer.Header().Set(renewedAccessTokenHeader, token.GetAccessToken())
		writer.Header().Set(renewedTokenTypeHeader, token.GetTokenType())
		writer.Header().Set(renewedExpiresInHeader, strconv.FormatInt(token.GetExpiresInSec(), 10))
	}

	httpkit.WriteOK(writer, request, appHeartbeatData{
		Accepted:      resp.GetAccepted(),
		HeartbeatAtMS: resp.GetHeartbeatAtMs(),
		ServerTimeMS:  resp.GetServerTimeMs(),
		AccessToken:   token.GetAccessToken(),
		TokenType:     token.GetTokenType(),
		ExpiresInSec:  token.GetExpiresInSec(),
	})
}
