package auth

import (
	"context"
	"log/slog"
	"strings"

	"hyapp/pkg/appcode"
	"hyapp/pkg/logx"
	authdomain "hyapp/services/user-service/internal/domain/auth"
)

// recordUserDevice 在认证成功后合并当前设备档案。
// 该写入是 best-effort：device_id 为空（老客户端/后台调用）直接跳过；写失败只记日志，
// 绝不让已经成功的登录/注册/refresh 因为设备画像落库失败而回吐错误。
func (s *Service) recordUserDevice(ctx context.Context, meta Meta, userID int64, deviceID string) {
	deviceID = strings.TrimSpace(deviceID)
	if s.authRepository == nil || userID <= 0 || deviceID == "" {
		return
	}

	nowMs := s.now().UnixMilli()
	device := authdomain.UserDevice{
		AppCode:      appcode.Normalize(meta.AppCode),
		UserID:       userID,
		DeviceID:     truncateDeviceField(deviceID, 128),
		Platform:     truncateDeviceField(normalizePlatform(meta.Platform), 32),
		DeviceModel:  truncateDeviceField(meta.DeviceModel, 128),
		Manufacturer: truncateDeviceField(meta.DeviceManufacturer, 64),
		OSVersion:    truncateDeviceField(meta.OSVersion, 64),
		IMEI:         truncateDeviceField(meta.IMEI, 64),
		AppVersion:   normalizeAuditClientVersion(meta.AppVersion),
		BuildNumber:  normalizeAuditClientVersion(meta.BuildNumber),
		// first_seen 只在 INSERT 生效；ON DUPLICATE KEY 更新时只有 last_seen/updated 前移。
		FirstSeenAtMs: nowMs,
		LastSeenAtMs:  nowMs,
		CreatedAtMs:   nowMs,
		UpdatedAtMs:   nowMs,
	}
	if err := s.authRepository.UpsertUserDevice(ctx, device); err != nil {
		// 失败必须可见：设备 tab 静默缺数据比登录多一条错误日志更难排查。
		logx.Error(
			logx.With(ctx, slog.String("request_id", meta.RequestID), slog.String("app_code", device.AppCode)),
			"user_device_upsert_failed",
			err,
			slog.String("component", "user_auth"),
			slog.Int64("user_id", userID),
			slog.String("device_id", device.DeviceID),
		)
	}
}

// deviceMetaWithRegistration 用注册 body 的设备字段补齐 Meta 缺口。
// 设备资料有两个来源：gateway 设备头（新客户端全局注入）和注册 body（旧协议字段）；
// 任意一侧可能单独缺失，落档案前统一取“先 header 后 body”的非空值。
func deviceMetaWithRegistration(meta Meta, registration authdomain.ThirdPartyRegistration) Meta {
	meta.Platform = firstNonEmpty(meta.Platform, registration.Platform)
	meta.DeviceModel = firstNonEmpty(meta.DeviceModel, registration.Device)
	meta.OSVersion = firstNonEmpty(meta.OSVersion, registration.OSVersion)
	meta.AppVersion = firstNonEmpty(meta.AppVersion, registration.AppVersion)
	meta.BuildNumber = firstNonEmpty(meta.BuildNumber, registration.BuildNumber)
	return meta
}

// truncateDeviceField 按列宽截断客户端可控字符串，超长上报不能让整条设备档案 INSERT 失败。
func truncateDeviceField(value string, maxRunes int) string {
	value = strings.TrimSpace(value)
	runes := []rune(value)
	if len(runes) <= maxRunes {
		return value
	}
	return string(runes[:maxRunes])
}
