"""
Module for nonce management and replay attack prevention.
"""

import hashlib
import logging
import time

import redis

logger = logging.getLogger(__name__)

# Constants
NONCE_TTL_SECONDS = 300  # 5 minutes TTL for nonce
TIMESTAMP_TOLERANCE_SECONDS = 30  # 30 seconds tolerance for timestamp

class NonceManager:
    """Nonce manager for replay attack prevention."""

    def __init__(self, redis_client: redis.Redis) -> None:
        """Initialize nonce manager.

        Args:
            redis_client: Redis client instance.
        """
        self.redis = redis_client
        self.nonce_ttl = NONCE_TTL_SECONDS
        self.timestamp_tolerance = TIMESTAMP_TOLERANCE_SECONDS
    
    def validate_nonce(
        self, client_nonce: bytes, timestamp: int, session_id: str
    ) -> bool:
        """
        Validate nonce uniqueness and timestamp validity.

        Args:
            client_nonce: Nonce from client.
            timestamp: Timestamp from client.
            session_id: Session ID.

        Returns:
            True if nonce is valid, False otherwise.
        """
        try:
            if not self._validate_timestamp(timestamp):
                logger.warning(
                    "Invalid timestamp",
                    extra={"timestamp": timestamp, "session_id": session_id},
                )
                return False

            nonce_key = self._create_nonce_key(client_nonce, session_id)
            nonce_hash = hashlib.sha256(client_nonce).hexdigest()[:16]

            if self.redis.exists(nonce_key):
                logger.warning(
                    "Nonce already used",
                    extra={"session_id": session_id, "nonce_hash": nonce_hash},
                )
                return False

            self.redis.setex(nonce_key, self.nonce_ttl, timestamp)

            logger.info(
                "Nonce validated successfully",
                extra={"session_id": session_id, "nonce_hash": nonce_hash},
            )

            return True

        except Exception as e:
            logger.error(
                "Nonce validation error",
                extra={"error": str(e), "session_id": session_id},
            )
            return False
    
    def _validate_timestamp(self, timestamp: int) -> bool:
        """Validate timestamp.

        Args:
            timestamp: Timestamp in milliseconds.

        Returns:
            True if timestamp is within tolerance, False otherwise.
        """
        current_time = int(time.time() * 1000)
        time_diff = abs(current_time - timestamp)
        return time_diff <= (self.timestamp_tolerance * 1000)
    
    def _create_nonce_key(self, client_nonce: bytes, session_id: str) -> str:
        """Create unique key for nonce in Redis.

        Args:
            client_nonce: Nonce from client.
            session_id: Session ID.

        Returns:
            Redis key string.
        """
        nonce_hash = hashlib.sha256(client_nonce).hexdigest()
        return f"nonce:{session_id}:{nonce_hash}"
    
    def cleanup_expired_nonces(self) -> int:
        """
        Cleanup expired nonces.

        Redis automatically removes keys by TTL, but this method provides
        additional cleanup for keys without TTL.

        Returns:
            Number of expired nonces removed.
        """
        try:
            pattern = "nonce:*"
            keys = self.redis.keys(pattern)

            expired_count = 0
            for key in keys:
                ttl = self.redis.ttl(key)
                if ttl == -1:
                    self.redis.delete(key)
                    expired_count += 1

            logger.info(
                "Nonce cleanup completed",
                extra={"expired_count": expired_count, "total_keys": len(keys)},
            )

            return expired_count

        except Exception as e:
            logger.error("Nonce cleanup error", extra={"error": str(e)})
            return 0

class ReplayProtection:
    """Replay attack protection."""

    def __init__(self, redis_client: redis.Redis) -> None:
        """Initialize replay protection.

        Args:
            redis_client: Redis client instance.
        """
        self.nonce_manager = NonceManager(redis_client)

    def validate_request(
        self, client_nonce: bytes, timestamp: int, session_id: str
    ) -> bool:
        """
        Validate request for replay attacks.

        Args:
            client_nonce: Nonce from client.
            timestamp: Timestamp from client.
            session_id: Session ID.

        Returns:
            True if request is valid, False otherwise.
        """
        return self.nonce_manager.validate_nonce(
            client_nonce, timestamp, session_id
        )

    def cleanup(self) -> int:
        """
        Cleanup expired nonces.

        Returns:
            Number of expired nonces removed.
        """
        return self.nonce_manager.cleanup_expired_nonces()
