package usertoken

import (
	"errors"
	"fmt"
	"time"
)

var ErrInvalidSessionToken = errors.New("invalid session token")

type TokenRevokedError struct {
	UserID                int64
	TokenID               int64
	MaxConcurrentSessions int64
}

func (e *TokenRevokedError) Error() string {
	return fmt.Sprintf("%s: user token revoked", ErrInvalidSessionToken)
}

func (e *TokenRevokedError) Unwrap() error { return ErrInvalidSessionToken }

// UserToken represents a user token
type UserToken struct {
	Id                int64
	UserId            int64
	ExternalSessionId int64
	AuthToken         string
	PrevAuthToken     string
	UserAgent         string
	ClientIp          string
	AuthTokenSeen     bool
	SeenAt            int64
	RotatedAt         int64
	CreatedAt         int64
	UpdatedAt         int64
	RevokedAt         int64
	UnhashedToken     string
}

const UrgentRotateTime = 1 * time.Minute

func (t *UserToken) NeedsRotation(rotationInterval time.Duration) bool {
	rotatedAt := time.Unix(t.RotatedAt, 0)
	if !t.AuthTokenSeen {
		return rotatedAt.Before(time.Now().Add(-UrgentRotateTime))
	}

	return rotatedAt.Before(time.Now().Add(-rotationInterval))
}

const rotationLeeway = 5 * time.Second

func (t *UserToken) NextRotation(rotationInterval time.Duration) time.Time {
	rotatedAt := time.Unix(t.RotatedAt, 0)
	return rotatedAt.Add(rotationInterval - rotationLeeway)
}
