import hmac
import hashlib
import time
from typing import Optional

class VoniSigner:
    @staticmethod
    def sign_request(api_key: str, method: str, path: str, body: str = "", timestamp: Optional[int] = None) -> str:
        """
        Generate an HMAC-SHA256 signature for a request.
        
        Args:
            api_key: The user's Voni API key
            method: HTTP method (GET, POST, etc.)
            path: The request path (e.g., /api/v1/projects/)
            body: The request body string (empty string for GET)
            timestamp: Unix timestamp (seconds). Defaults to current time.
            
        Returns:
            The hex signature
        """
        if timestamp is None:
            timestamp = int(time.time())
            
        message = f"{timestamp}{method.upper()}{path}{body}"
        
        signature = hmac.new(
            api_key.encode("utf-8"),
            message.encode("utf-8"),
            hashlib.sha256
        ).hexdigest()
        
        return signature

    @staticmethod
    def verify_signature(
        signature: str,
        api_key: str,
        method: str,
        path: str,
        body: str = "",
        timestamp: int = 0,
        tolerance_in_seconds: int = 300
    ) -> bool:
        """
        Verify an incoming request signature.
        Raises ValueError if timestamp is too old.
        """
        now = int(time.time())
        
        # 1. Check timestamp freshness (Replay Attack Protection)
        if abs(now - timestamp) > tolerance_in_seconds:
            raise ValueError("Request timestamp is too old (possible replay attack).")
            
        # 2. Re-compute signature
        expected_signature = VoniSigner.sign_request(
            api_key=api_key,
            method=method,
            path=path,
            body=body,
            timestamp=timestamp
        )
        
        # 3. Constant-time comparison
        return hmac.compare_digest(signature, expected_signature)
