package services

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

// SessionService 인메모리 세션 스토어
type SessionService struct {
	sessions sync.Map      // sessionID → time.Time(만료시각)
	ttl      time.Duration // 세션 유효 기간
}

var sessionServiceInstance *SessionService
var sessionServiceOnce sync.Once

// GetSessionService 세션 서비스 싱글톤 반환
func GetSessionService() *SessionService {
	sessionServiceOnce.Do(func() {
		sessionServiceInstance = NewSessionService()
	})
	return sessionServiceInstance
}

// NewSessionService 세션 서비스 초기화 (TTL 24시간)
func NewSessionService() *SessionService {
	svc := &SessionService{ttl: 24 * time.Hour}
	go svc.cleanup()
	return svc
}

// Create 새 세션 생성 → sessionID(UUID) 반환
func (s *SessionService) Create() string {
	b := make([]byte, 16)
	_, _ = rand.Read(b)
	id := hex.EncodeToString(b)
	s.sessions.Store(id, time.Now().Add(s.ttl))
	return id
}

// Validate 세션 유효성 검사 (만료 시 자동 삭제)
func (s *SessionService) Validate(id string) bool {
	val, ok := s.sessions.Load(id)
	if !ok {
		return false
	}
	expiry, ok := val.(time.Time)
	if !ok || time.Now().After(expiry) {
		s.sessions.Delete(id)
		return false
	}
	return true
}

// Delete 세션 삭제 (로그아웃)
func (s *SessionService) Delete(id string) {
	s.sessions.Delete(id)
}

// cleanup 만료된 세션을 주기적으로 정리 (1시간 주기)
func (s *SessionService) cleanup() {
	ticker := time.NewTicker(time.Hour)
	defer ticker.Stop()
	for range ticker.C {
		now := time.Now()
		s.sessions.Range(func(key, val any) bool {
			if expiry, ok := val.(time.Time); ok && now.After(expiry) {
				s.sessions.Delete(key)
			}
			return true
		})
	}
}
