// Package auth 定义 user-service 认证领域模型，不包含密码明文或三方 SDK 细节。
package auth

// PasswordAccount 是用户主动设置密码后的密码身份记录。
// 登录入口使用展示号事实表解析用户；held 默认短号可以作为 active 靓号的登录别名，不再维护独立账号命名空间。
type PasswordAccount struct {
	// AppCode 是账号所属 App，短号只在同一个 App 内唯一。
	AppCode string
	// UserID 是密码身份绑定的系统用户 ID。
	UserID int64
	// DisplayUserID 是登录成功后应签发给客户端的当前展示号；用户用 held 默认短号登录时这里仍返回 active 靓号。
	DisplayUserID string
	// PasswordHash 保存 bcrypt 等安全 hash，永远不保存密码明文。
	PasswordHash string
	// HashAlg 标记 hash 算法，方便后续升级算法。
	HashAlg string
	// CreatedAtMs 是密码身份创建时间。
	CreatedAtMs int64
	// UpdatedAtMs 是密码身份更新时间。
	UpdatedAtMs int64
}

// Token 表达 user-service 签发给 gateway 的登录结果。
// refresh token 原文只能出现在返回路径，持久化层必须保存 hash。
type Token struct {
	// AppCode 是 access/refresh session 绑定的 App 租户键。
	AppCode string
	// UserID 是系统内部不可变用户 ID。
	UserID int64
	// DisplayUserID 是当前展示短号，可能是默认短号或有效靓号。
	DisplayUserID string
	// DefaultDisplayUserID 是用户永久默认短号。
	DefaultDisplayUserID string
	// DisplayUserIDKind 表示当前展示号来源。
	DisplayUserIDKind string
	// DisplayUserIDExpiresAtMs 是当前靓号过期时间，默认短号为 0。
	DisplayUserIDExpiresAtMs int64
	// ProfileCompleted 是 access token 中用于 gateway profile gate 的资料完成快照。
	ProfileCompleted bool
	// OnboardingStatus 是 access token 中用于客户端跳转的注册状态。
	OnboardingStatus string
	// SessionID 是服务端 refresh session 标识。
	SessionID string
	// AccessToken 是返回给 gateway/client 的 JWT。
	AccessToken string
	// RefreshToken 是一次性轮换的 refresh token 原文，只能在响应中出现。
	RefreshToken string
	// ExpiresInSec 是 access token 有效期秒数。
	ExpiresInSec int64
	// TokenType 固定为 Bearer。
	TokenType string
}

// Session 表达服务端会话和 refresh token 生命周期。
type Session struct {
	// AppCode 是 session 所属 App，refresh token 不能跨 App 复用。
	AppCode string
	// SessionID 是服务端会话主键。
	SessionID string
	// UserID 是会话所属用户。
	UserID int64
	// RefreshTokenHash 是 refresh token 的 hash，持久化层不得保存原文。
	RefreshTokenHash string
	// TokenFamilyID 把一次登录后连续轮换出的 session 串成同一个安全边界；检测到重放时整族失效。
	TokenFamilyID string
	// Generation 是 session 在 token family 内的单调代际，首个登录 session 为 0。
	Generation int64
	// ParentSessionID 指向直接上一代 session；只有直接父代允许命中短暂轮换宽限期。
	ParentSessionID string
	// RotatedToSessionID 只在已成功轮换的父 session 上有值，用于恢复同一次轮换的幂等响应。
	RotatedToSessionID string
	// RotationAtMs 是父 session 被轮换的 UTC epoch ms，宽限期只能从该事实时间开始计算。
	RotationAtMs int64
	// RotationRequestID 保存首次消费该 refresh token 的客户端幂等键。
	RotationRequestID string
	// DeviceID 绑定 refresh token 轮换设备，防止跨设备复用。
	DeviceID string
	// ExpiresAtMs 是 refresh session 过期时间。
	ExpiresAtMs int64
	// LastHeartbeatAtMs 是当前 App 会话最近一次被客户端心跳确认的时间。
	LastHeartbeatAtMs int64
	// LastHeartbeatRequestID 保存最近一次 App 心跳链路 ID，方便按 request_id 反查客户端在线刷新。
	LastHeartbeatRequestID string
	// RevokedAtMs 非 0 表示会话已吊销。
	RevokedAtMs int64
	// RevokedReason 区分 logout、refresh 轮换、后台封禁和 IP 风控撤销。
	RevokedReason string
	// RevokedRequestID 串联触发撤销的登录请求或后台任务。
	RevokedRequestID string
	// RevokedBy 标识撤销来源，例如 user_logout、refresh_rotate、risk_worker。
	RevokedBy string
	// CreatedAtMs 是会话创建时间。
	CreatedAtMs int64
	// UpdatedAtMs 是会话更新时间。
	UpdatedAtMs int64
}

// RefreshRotationStatus 是 repository 对一次 refresh 消费的原子判定。
type RefreshRotationStatus string

const (
	// RefreshRotationCreated 表示当前 refresh token 首次被消费并成功产生下一代。
	RefreshRotationCreated RefreshRotationStatus = "created"
	// RefreshRotationGraceHit 表示直接父代在宽限期内重试，必须复用首次落库的同一 token pair。
	RefreshRotationGraceHit RefreshRotationStatus = "grace_hit"
	// RefreshRotationReuseDetected 表示旧 token 已越过直接父代或宽限期，整条 token family 已被吊销。
	RefreshRotationReuseDetected RefreshRotationStatus = "reuse_detected"
)

// RefreshRotationCommand 把候选下一代和加密幂等响应交给 repository 原子提交。
// TokenCiphertext 是 AES-GCM 密文，数据库永远不保存 access/refresh token 原文。
type RefreshRotationCommand struct {
	AppCode          string
	RefreshTokenHash string
	DeviceID         string
	RefreshRequestID string
	NowMs            int64
	GracePeriodMs    int64
	// DenyUntilMs 固化本次撤销涉及 access JWT 的最晚拒绝时刻，不能被未来 TTL 配置缩短。
	DenyUntilMs        int64
	NewSession         Session
	TokenCiphertext    []byte
	OutcomeExpiresAtMs int64
}

// RefreshRotationResult 返回轮换、宽限复用或重放撤销的持久化事实。
type RefreshRotationResult struct {
	Status             RefreshRotationStatus
	SourceSession      Session
	ActiveSession      Session
	RefreshRequestID   string
	TokenCiphertext    []byte
	FamilySessionIDs   []string
	FamilyNewlyRevoked bool
}

// SessionDenylistJob 是 MySQL 持久化的 gateway Redis denylist 补偿事实。
// family revoke 与 job 同事务提交，避免 MySQL 已撤销而进程崩溃导致旧 access JWT 永久漏拦截。
type SessionDenylistJob struct {
	JobID     int64
	AppCode   string
	SessionID string
	Reason    string
	Attempts  int
	// DenyUntilMs 是该 sid 的历史 access JWT 全部自然过期（含安全余量）的时刻。
	DenyUntilMs int64
	CreatedAtMs int64
}

// ThirdPartyIdentity 是 provider + subject 到用户的稳定绑定。
type ThirdPartyIdentity struct {
	// AppCode 把 provider subject 限定在当前 App 内，避免多个 App 共享 provider 命名空间。
	AppCode string
	// UserID 是绑定到的系统用户。
	UserID int64
	// Provider 是三方平台标识，例如 wechat。
	Provider string
	// ProviderSubject 是 provider 内稳定用户标识。
	ProviderSubject string
	// ProviderUnionID 是 provider 可选的跨应用联合 ID。
	ProviderUnionID string
	// CreatedAtMs 是绑定创建时间。
	CreatedAtMs int64
	// UpdatedAtMs 是绑定更新时间。
	UpdatedAtMs int64
}

// LoginAudit 是登录注册链路的审计记录。
// 审计不能包含密码、三方 credential 或 refresh token 原文。
type LoginAudit struct {
	// AppCode 是本次认证链路所属 App。
	AppCode string
	// RequestID 是 gateway 透传的请求 ID，用于串联审计。
	RequestID string
	// UserID 是已知用户 ID，认证失败且未解析身份时可以为 0。
	UserID int64
	// LoginType 区分 password、third_party、refresh、logout 等链路。
	LoginType string
	// Provider 只在三方登录链路中有值。
	Provider string
	// Channel 是后台展示维度，固定为 account/google/facebook/twitter/tiktok 等稳定渠道。
	Channel string
	// Platform 是客户端平台快照，例如 android/ios。
	Platform string
	// AppVersion 是本次认证请求携带的客户端语义版本；空值表示客户端未上报，不能回退到注册版本。
	AppVersion string
	// BuildNumber 是本次认证请求携带的精确构建号，用于区分同一语义版本的不同安装包。
	BuildNumber string
	// Result 是 success 或 failed。
	Result string
	// FailureCode 保存稳定错误 reason，不能写敏感凭证。
	FailureCode string
	// ClientIP 是 gateway 观察到的客户端 IP。
	ClientIP string
	// IPCountryCode 是 IP Geo 解析出的国家码，未解析时为空。
	IPCountryCode string
	// Blocked 标记本次登录是否被入口或异步风控阻断。
	Blocked bool
	// BlockReason 保存 language/timezone/ip_cache/ip_async 等稳定阻断原因。
	BlockReason string
	// UserAgent 是客户端 UA。
	UserAgent string
	// CreatedAtMs 是审计写入时间。
	CreatedAtMs int64
}

// UserDevice 是认证成功后按 (app_code, user_id, device_id) 聚合的设备档案快照。
// 它只服务后台设备画像展示，不参与登录判定；字段允许为空，客户端上报能力决定完整度。
type UserDevice struct {
	// AppCode 是设备档案所属 App 租户键。
	AppCode string
	// UserID 是设备归属用户。
	UserID int64
	// DeviceID 与 auth_sessions.device_id 同源（android_<ANDROID_ID> / ios_<IDFV>）。
	DeviceID string
	// Platform 是客户端平台快照，例如 android/ios。
	Platform string
	// DeviceModel 是设备型号，例如 Redmi Note 8 Pro。
	DeviceModel string
	// Manufacturer 是设备厂商，例如 Xiaomi/Apple。
	Manufacturer string
	// OSVersion 是系统版本，例如 Android 的 "13" 或 iOS 的 "17.5"。
	OSVersion string
	// IMEI 在 Android 10+ 无特权权限时为空，字段保留给可获取的旧设备。
	IMEI string
	// AppVersion 是最近一次认证成功时的客户端语义版本。
	AppVersion string
	// BuildNumber 是最近一次认证成功时的客户端构建号。
	BuildNumber string
	// FirstSeenAtMs 是该设备首次通过认证的时间。
	FirstSeenAtMs int64
	// LastSeenAtMs 是该设备最近一次认证成功时间，后台按它倒序展示设备列表。
	LastSeenAtMs int64
	// CreatedAtMs 是档案创建时间。
	CreatedAtMs int64
	// UpdatedAtMs 是档案更新时间。
	UpdatedAtMs int64
}

// ThirdPartyProfile 是三方凭证校验后的稳定身份结果。
type ThirdPartyProfile struct {
	// ProviderSubject 是三方平台内稳定身份。
	ProviderSubject string
	// ProviderUnionID 是可选联合身份。
	ProviderUnionID string
}

// ThirdPartyRegistration 是三方首次注册时写入用户主表的资料和来源快照。
// 它不包含三方 credential 原文；credential 只在 verifier 中短暂使用。
type ThirdPartyRegistration struct {
	// AppCode 是注册用户所属 App，必须来自 gateway 解析后的 RequestMeta。
	AppCode string
	// Username 是客户端提交的展示名。
	Username string
	// Gender 是客户端提交的性别原值，服务端不根据它推断身份。
	Gender string
	// Country 是客户端提交的国家码；服务端会归一并要求命中 active countries.country_code。
	Country string
	// RegionID 是 user-service 根据 Country 解析出的区域快照，不接受客户端直接提交。
	RegionID int64
	// InviteCode 是可选邀请码。
	InviteCode string
	// IP 是注册入口上报或 gateway 观察到的 IP。
	IP string
	// UserAgent 是 gateway 从 HTTP header 观察到的客户端 UA。
	UserAgent string
	// CountryByIP 是服务端根据入口 IP 或可信边缘地域信息得到的国家快照。
	CountryByIP string
	// DeviceID 是注册设备 ID，同时用于 refresh session 绑定。
	DeviceID string
	// Device 是客户端上报的设备型号或描述。
	Device string
	// OSVersion 是客户端系统版本。
	OSVersion string
	// Avatar 是头像 HTTP(S) URL。
	Avatar string
	// BirthDate 使用 yyyy-mm-dd 保存生日，不携带时区。
	BirthDate string
	// AppVersion 是注册客户端版本。
	AppVersion string
	// BuildNumber 是注册客户端构建号，比 app_version 更适合定位精确包。
	BuildNumber string
	// Source 是注册来源渠道。
	Source string
	// InstallChannel 是安装渠道，例如 play_store 或 app_store。
	InstallChannel string
	// Campaign 是投放活动标识。
	Campaign string
	// Platform 是客户端平台，当前支持 android 或 ios。
	Platform string
	// Language 是客户端语言偏好。
	Language string
	// Timezone 是客户端 IANA 时区，例如 America/Los_Angeles。
	Timezone string
}
