package services

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"time"

	"github.com/redis/go-redis/v9"
)

// TokenBlacklist gère la blacklist de tokens JWT pour invalider les tokens après logout ou révocation
// T0174: Service pour gérer la blacklist de tokens avec Redis
type TokenBlacklist struct {
	client *redis.Client
	prefix string // Préfixe pour les clés Redis (ex: "token_blacklist:")
}

// NewTokenBlacklist crée une nouvelle instance de TokenBlacklist
// T0174: Crée un service TokenBlacklist avec Redis
func NewTokenBlacklist(client *redis.Client) *TokenBlacklist {
	return &TokenBlacklist{
		client: client,
		prefix: "token_blacklist:",
	}
}

// Add ajoute un token à la blacklist avec un TTL
// T0174: Ajoute un token à la blacklist avec expiration automatique
func (tb *TokenBlacklist) Add(ctx context.Context, token string, ttl time.Duration) error {
	tokenHash := tb.hashToken(token)
	key := tb.prefix + tokenHash

	// T0174: Ajouter le token à Redis avec TTL pour expiration automatique
	err := tb.client.Set(ctx, key, "1", ttl).Err()
	if err != nil {
		return fmt.Errorf("failed to add token to blacklist: %w", err)
	}

	return nil
}

// IsBlacklisted vérifie si un token est dans la blacklist
// T0174: Vérifie si un token est blacklisté
func (tb *TokenBlacklist) IsBlacklisted(ctx context.Context, token string) (bool, error) {
	tokenHash := tb.hashToken(token)
	key := tb.prefix + tokenHash

	// T0174: Vérifier si la clé existe dans Redis
	exists, err := tb.client.Exists(ctx, key).Result()
	if err != nil {
		return false, fmt.Errorf("failed to check token blacklist: %w", err)
	}

	return exists > 0, nil
}

// Remove supprime un token de la blacklist (optionnel, utile pour tests)
func (tb *TokenBlacklist) Remove(ctx context.Context, token string) error {
	tokenHash := tb.hashToken(token)
	key := tb.prefix + tokenHash

	err := tb.client.Del(ctx, key).Err()
	if err != nil {
		return fmt.Errorf("failed to remove token from blacklist: %w", err)
	}

	return nil
}

// AddTokenHash ajoute un token hash directement à la blacklist (T0206)
// Cette méthode permet d'ajouter un tokenHash sans le re-hasher
func (tb *TokenBlacklist) AddTokenHash(ctx context.Context, tokenHash string, ttl time.Duration) error {
	key := tb.prefix + tokenHash

	// Ajouter le tokenHash à Redis avec TTL pour expiration automatique
	err := tb.client.Set(ctx, key, "1", ttl).Err()
	if err != nil {
		return fmt.Errorf("failed to add token hash to blacklist: %w", err)
	}

	return nil
}

// hashToken hash un token avec SHA-256 pour la sécurité
func (tb *TokenBlacklist) hashToken(token string) string {
	hash := sha256.Sum256([]byte(token))
	return hex.EncodeToString(hash[:])
}
