package auth

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"time"

	"golang.org/x/crypto/bcrypt"
)

// Token is a record in personal_access_tokens.
type Token struct {
	ID            int64
	TokenableType string
	TokenableID   int64 // users.id
	Name          string
	TokenHash     string // sha256 hex of the plain tunnel token
	Abilities     string
	LastUsedAt    *time.Time
	ExpiresAt     *time.Time
	CreatedAt     time.Time
}

// tokenTTL is how long tokens stay valid; THROTTLING and TTL from config in
// service. Kept as package var so tests can shrink it.
var tokenTTL = 24 * time.Hour

// dummyTokenHash is a constant bcrypt hash used to equalize login timing on the
// not-found/disabled failure paths (L1). It is never stored and its plaintext is
// irrelevant; it only exists so every failed login pays one bcrypt comparison.
var dummyTokenHash = func() []byte {
	h, _ := bcrypt.GenerateFromPassword([]byte("no-such-account-dummy-placeholder"), bcrypt.DefaultCost)
	return h
}()

// IssueToken creates a new opaque token: returns the PLAINTEXT value (given to
// the client once) and its sha256 hex hash (what is stored in the DB).
//
// crypto/rand.Text returns >=128 bits of entropy and has no predictable
// fallback, so a token is never derived from a time seed (L3).
func IssueToken() (plain string, hash string) {
	plain = rand.Text()
	return plain, HashToken(plain)
}

// HashToken hashes a token the way Sanctum stores it: sha256 hex.
func HashToken(plain string) string {
	sum := sha256.Sum256([]byte(plain))
	return hex.EncodeToString(sum[:])
}
