package game

import (
	"strconv"
	"strings"

	jwt "github.com/golang-jwt/jwt/v5"
	"hyapp/pkg/appcode"
	"hyapp/pkg/xerr"
	gamedomain "hyapp/services/game-service/internal/domain/game"
)

func (s *Service) appSessionFromAccessToken(app string, token string) (gamedomain.LaunchSession, error) {
	// ZeeOne/灵仙都直接把 App access token 作为厂商 sessionId/token；game-service 不持有 JWT secret，
	// 这里只消费 token 内部用户快照并校验 exp/app_code，入口签名仍由厂商 AppSecret 负责。
	claims := jwt.MapClaims{}
	_, _, err := new(jwt.Parser).ParseUnverified(strings.TrimSpace(token), claims)
	if err != nil {
		return gamedomain.LaunchSession{}, xerr.New(xerr.Unauthorized, "token invalid")
	}
	if typ := strings.TrimSpace(jwtStringClaim(claims, "typ")); typ != "" && typ != "access" {
		return gamedomain.LaunchSession{}, xerr.New(xerr.Unauthorized, "token invalid")
	}
	expiresAt, err := claims.GetExpirationTime()
	if err != nil || expiresAt == nil || !expiresAt.After(s.now()) {
		return gamedomain.LaunchSession{}, xerr.New(xerr.SessionExpired, "token expired")
	}
	tokenApp := appcode.Normalize(jwtStringClaim(claims, "app_code"))
	if tokenApp != "" && tokenApp != appcode.Normalize(app) {
		return gamedomain.LaunchSession{}, xerr.New(xerr.Unauthorized, "token invalid")
	}
	userID, err := strconv.ParseInt(strings.TrimSpace(jwtStringClaim(claims, "user_id")), 10, 64)
	if err != nil || userID <= 0 {
		return gamedomain.LaunchSession{}, xerr.New(xerr.Unauthorized, "token invalid")
	}
	displayUserID := firstNonEmpty(
		jwtStringClaim(claims, "display_user_id"),
		jwtStringClaim(claims, "default_display_user_id"),
		strconv.FormatInt(userID, 10),
	)
	return gamedomain.LaunchSession{
		AppCode:       tokenApp,
		SessionID:     jwtStringClaim(claims, "sid"),
		UserID:        userID,
		DisplayUserID: displayUserID,
		Status:        gamedomain.SessionActive,
		ExpiresAtMS:   expiresAt.UnixMilli(),
	}, nil
}

func jwtStringClaim(claims jwt.MapClaims, key string) string {
	value, _ := claims[key].(string)
	return strings.TrimSpace(value)
}
