package services

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

	"gorm.io/gorm"
	"veza-backend-api/internal/models"
)

// RefreshTokenService gère le stockage et la validation des refresh tokens
// T0164: Service pour gérer les refresh tokens avec stockage en base et validation
type RefreshTokenService struct {
	db *gorm.DB
}

// NewRefreshTokenService crée une nouvelle instance de RefreshTokenService
func NewRefreshTokenService(db *gorm.DB) *RefreshTokenService {
	return &RefreshTokenService{db: db}
}

// Store stocke un refresh token en base de données (hashé pour la sécurité)
// T0164: Stocke le token hashé avec userID et expiration
func (s *RefreshTokenService) Store(userID int64, token string, expiresAt time.Time) error {
	tokenHash := s.hashToken(token)
	
	refreshToken := &models.RefreshToken{
		UserID:    userID,
		TokenHash: tokenHash,
		ExpiresAt: expiresAt,
	}
	
	return s.db.Create(refreshToken).Error
}

// Validate vérifie si un refresh token est valide
// T0164: Valide le token en vérifiant son hash et sa date d'expiration
func (s *RefreshTokenService) Validate(userID int64, token string) (bool, error) {
	tokenHash := s.hashToken(token)
	
	var refreshToken models.RefreshToken
	err := s.db.Where("user_id = ? AND token_hash = ?", userID, tokenHash).
		First(&refreshToken).Error
	
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return false, nil
		}
		return false, err
	}
	
	// Vérifier si le token n'a pas expiré
	if time.Now().After(refreshToken.ExpiresAt) {
		return false, nil
	}
	
	return true, nil
}

// Revoke supprime/révoque un refresh token
// T0164: Supprime le token de la base de données
func (s *RefreshTokenService) Revoke(userID int64, token string) error {
	tokenHash := s.hashToken(token)
	
	result := s.db.Where("user_id = ? AND token_hash = ?", userID, tokenHash).
		Delete(&models.RefreshToken{})
	
	if result.Error != nil {
		return result.Error
	}
	
	if result.RowsAffected == 0 {
		return errors.New("refresh token not found")
	}
	
	return nil
}

// RevokeAll révoque tous les refresh tokens d'un utilisateur
// Utile pour la déconnexion de tous les appareils
func (s *RefreshTokenService) RevokeAll(userID int64) error {
	result := s.db.Where("user_id = ?", userID).
		Delete(&models.RefreshToken{})
	
	return result.Error
}

// hashToken hash un token avec SHA-256 pour le stockage sécurisé
func (s *RefreshTokenService) hashToken(token string) string {
	hash := sha256.Sum256([]byte(token))
	return hex.EncodeToString(hash[:])
}

// HashToken expose la méthode hashToken pour les tests
// T0172: Méthode publique pour hasher les tokens (utilisée dans les tests)
func (s *RefreshTokenService) HashToken(token string) string {
	return s.hashToken(token)
}

