package player

import (
	"crypto/rand"
	"encoding/hex"
	"sync"
	"time"
)

// Session holds an authenticated player's session state.
type Session struct {
	Token      string
	PlayerID   uint64
	PlayerName string
	CreatedAt  time.Time
	LastActive time.Time
}

// SessionManager manages active sessions.
type SessionManager struct {
	mu       sync.RWMutex
	sessions map[string]*Session // token -> session
}

// NewSessionManager creates a new session manager.
func NewSessionManager() *SessionManager {
	return &SessionManager{
		sessions: make(map[string]*Session),
	}
}

// Create generates a new session for the given player.
func (sm *SessionManager) Create(playerID uint64, playerName string) *Session {
	token := generateToken()
	now := time.Now()

	s := &Session{
		Token:      token,
		PlayerID:   playerID,
		PlayerName: playerName,
		CreatedAt:  now,
		LastActive: now,
	}

	sm.mu.Lock()
	sm.sessions[token] = s
	sm.mu.Unlock()

	return s
}

// Get retrieves a session by token. Returns nil if not found.
func (sm *SessionManager) Get(token string) *Session {
	sm.mu.RLock()
	defer sm.mu.RUnlock()
	s := sm.sessions[token]
	if s != nil {
		s.LastActive = time.Now()
	}
	return s
}

// Remove deletes a session.
func (sm *SessionManager) Remove(token string) {
	sm.mu.Lock()
	delete(sm.sessions, token)
	sm.mu.Unlock()
}

// CleanupExpired removes sessions inactive for longer than the given duration.
func (sm *SessionManager) CleanupExpired(maxIdle time.Duration) int {
	sm.mu.Lock()
	defer sm.mu.Unlock()

	cutoff := time.Now().Add(-maxIdle)
	removed := 0
	for token, s := range sm.sessions {
		if s.LastActive.Before(cutoff) {
			delete(sm.sessions, token)
			removed++
		}
	}
	return removed
}

func generateToken() string {
	b := make([]byte, 32)
	_, _ = rand.Read(b)
	return hex.EncodeToString(b)
}
