package domain

import "time"

// DeviceToken 表示裝置與 Token 之間的關聯
type DeviceToken struct {
	DeviceID string // 裝置的唯一標識符
	TokenID  string // Token 的唯一標識符
}

type UIDToken map[string]int64

// Ticket 表示一次性使用的 Token 結構，包含數據和 Token 資訊
type Ticket struct {
	Data  any   `json:"data"`  // 任意附加數據
	Token Token `json:"token"` // 一次性使用的 Token 資訊
}

// Token 表示使用者的存取和刷新 Token 資訊
type Token struct {
	ID               string    `json:"id"`                 // Token 的唯一標識符
	UID              string    `json:"uid"`                // 用戶的唯一標識符
	DeviceID         string    `json:"device_id"`          // 裝置的唯一標識符
	AccessToken      string    `json:"access_token"`       // 存取 Token
	ExpiresIn        int       `json:"expires_in"`         // 存取 Token 的有效時長（秒）
	AccessCreateAt   time.Time `json:"access_create_at"`   // 存取 Token 的創建時間
	RefreshToken     string    `json:"refresh_token"`      // 刷新 Token
	RefreshExpiresIn int       `json:"refresh_expires_in"` // 刷新 Token 的有效時長（秒）
	RefreshCreateAt  time.Time `json:"refresh_create_at"`  // 刷新 Token 的創建時間
}

// AccessTokenExpires 返回存取 Token 的有效期（以秒為單位）。
func (t *Token) AccessTokenExpires() time.Duration {
	return time.Duration(t.ExpiresIn) * time.Second
}

// RefreshTokenExpires 返回刷新 Token 的有效期（以秒為單位）。
func (t *Token) RefreshTokenExpires() time.Duration {
	return time.Duration(t.RefreshExpiresIn) * time.Second
}

// RefreshTokenExpiresUnix 返回刷新 Token 的到期時間（UnixNano 時間戳）。
func (t *Token) RefreshTokenExpiresUnix() int64 {
	return time.Now().Add(t.RefreshTokenExpires()).UnixNano()
}

// IsExpires 檢查存取 Token 是否已過期。如果存取 Token 的創建時間加上其有效期早於當前時間，則返回 true。
func (t *Token) IsExpires() bool {
	return t.AccessCreateAt.Add(t.AccessTokenExpires()).Before(time.Now())
}

// RedisExpiredSec 返回存取 Token 在 Redis 中的剩餘有效時間（秒）。計算方法為：從到期時間的 Unix 時間戳減去當前時間。
func (t *Token) RedisExpiredSec() int64 {
	sec := time.Unix(int64(t.ExpiresIn), 0).Sub(time.Now().UTC())

	return int64(sec.Seconds())
}

// RedisRefreshExpiredSec 返回刷新 Token 在 Redis 中的剩餘有效時間（秒）。計算方法為：從刷新到期時間的 Unix 時間戳減去當前時間。
func (t *Token) RedisRefreshExpiredSec() int64 {
	sec := time.Unix(int64(t.RefreshExpiresIn), 0).Sub(time.Now().UTC())

	return int64(sec.Seconds())
}
