package auth

import (
	"context"
	"time"

	"github.com/rs/zerolog/log"
)

// SessionCleaner runs periodic cleanup of expired sessions.
type SessionCleaner struct {
	repo     SessionCleanupRepo
	interval time.Duration
	maxAge   time.Duration
	stopCh   chan struct{}
}

// SessionCleanupRepo is the minimal interface required by SessionCleaner.
type SessionCleanupRepo interface {
	CleanupExpiredSessions(ctx context.Context, olderThan time.Duration) (int64, error)
}

// NewSessionCleaner creates a new SessionCleaner.
// interval: how often to run cleanup (e.g., 1 hour).
// maxAge: delete sessions older than this (e.g., 7 days).
func NewSessionCleaner(repo SessionCleanupRepo, interval, maxAge time.Duration) *SessionCleaner {
	return &SessionCleaner{
		repo:     repo,
		interval: interval,
		maxAge:   maxAge,
		stopCh:   make(chan struct{}),
	}
}

// Start begins the cleanup loop in a goroutine.
func (sc *SessionCleaner) Start() {
	go sc.run()
}

// Stop gracefully stops the cleanup loop.
func (sc *SessionCleaner) Stop() {
	close(sc.stopCh)
}

func (sc *SessionCleaner) run() {
	ticker := time.NewTicker(sc.interval)
	defer ticker.Stop()

	// Run once immediately on start.
	sc.cleanup()

	for {
		select {
		case <-ticker.C:
			sc.cleanup()
		case <-sc.stopCh:
			return
		}
	}
}

func (sc *SessionCleaner) cleanup() {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	deleted, err := sc.repo.CleanupExpiredSessions(ctx, sc.maxAge)
	if err != nil {
		log.Error().Err(err).Msg("Session cleanup failed")
		return
	}
	if deleted > 0 {
		log.Info().Int64("deleted", deleted).Msg("Session cleanup completed")
	}
}
