"""
Authentication module for OCPP WebSocket server
Handles token-based authentication for EVSE connections
"""
import logging
import hashlib
import hmac
import time
from typing import Optional, Set
import os

from .config import get_config

logger = logging.getLogger(__name__)


class TokenAuthenticator:
    """Token-based authentication for EVSE connections"""
    
    def __init__(self):
        self.config = get_config()
        self._valid_tokens: Set[str] = set()
        self._load_tokens()
    
    def _load_tokens(self):
        """Load valid tokens from configuration"""
        # Load from environment variable (comma-separated)
        env_tokens = os.getenv('EVSE_TOKENS', '')
        if env_tokens:
            tokens = [token.strip() for token in env_tokens.split(',')]
            self._valid_tokens.update(tokens)
            logger.info(f"Loaded {len(tokens)} tokens from environment")
        
        # Add admin token if available
        if self.config.admin_token:
            self._valid_tokens.add(self.config.admin_token)
            logger.info("Added admin token to valid tokens")
        
        # Add default development tokens if no tokens configured
        if not self._valid_tokens:
            default_tokens = [
                "evse-dev-token-001",
                "evse-dev-token-002", 
                "voltie-evse-key",
                "development-token"
            ]
            self._valid_tokens.update(default_tokens)
            logger.warning(f"No tokens configured, using default development tokens: {len(default_tokens)}")
    
    def validate_token(self, token: str) -> bool:
        """Validate an authentication token"""
        if not token:
            return False
        
        # Check against configured tokens
        if token in self._valid_tokens:
            logger.debug(f"Token validation successful: {token[:10]}...")
            return True
        
        # Check if it's a time-based token (if implemented)
        if self._validate_time_based_token(token):
            logger.debug(f"Time-based token validation successful: {token[:10]}...")
            return True
        
        logger.warning(f"Token validation failed: {token[:10]}...")
        return False
    
    def _validate_time_based_token(self, token: str) -> bool:
        """Validate time-based tokens (optional implementation)"""
        try:
            # Example time-based token format: timestamp.signature
            if '.' not in token:
                return False
            
            timestamp_str, signature = token.split('.', 1)
            timestamp = int(timestamp_str)
            
            # Check if token is not too old (5 minutes)
            current_time = int(time.time())
            if current_time - timestamp > 300:  # 5 minutes
                logger.debug("Time-based token expired")
                return False
            
            # Verify signature (if secret key is configured)
            secret_key = os.getenv('TOKEN_SECRET_KEY', 'default-secret')
            expected_signature = hmac.new(
                secret_key.encode(),
                timestamp_str.encode(),
                hashlib.sha256
            ).hexdigest()[:16]  # First 16 chars
            
            return hmac.compare_digest(signature, expected_signature)
        
        except (ValueError, TypeError):
            return False
    
    def add_token(self, token: str) -> bool:
        """Add a new valid token"""
        if token and token not in self._valid_tokens:
            self._valid_tokens.add(token)
            logger.info(f"Added new token: {token[:10]}...")
            return True
        return False
    
    def remove_token(self, token: str) -> bool:
        """Remove a token"""
        if token in self._valid_tokens:
            self._valid_tokens.remove(token)
            logger.info(f"Removed token: {token[:10]}...")
            return True
        return False
    
    def get_token_count(self) -> int:
        """Get number of valid tokens"""
        return len(self._valid_tokens)
    
    def generate_development_token(self, charger_id: str) -> str:
        """Generate a development token for testing"""
        timestamp = int(time.time())
        secret_key = os.getenv('TOKEN_SECRET_KEY', 'default-secret')
        
        # Create token: charger_id.timestamp.signature
        payload = f"{charger_id}.{timestamp}"
        signature = hmac.new(
            secret_key.encode(),
            payload.encode(),
            hashlib.sha256
        ).hexdigest()[:16]
        
        token = f"{payload}.{signature}"
        
        # Add to valid tokens for immediate use
        self.add_token(token)
        
        logger.info(f"Generated development token for {charger_id}")
        return token


# Global authenticator instance
_authenticator: Optional[TokenAuthenticator] = None


def get_authenticator() -> TokenAuthenticator:
    """Get the global authenticator instance"""
    global _authenticator
    if _authenticator is None:
        _authenticator = TokenAuthenticator()
    return _authenticator


def validate_token(token: str) -> bool:
    """Validate an authentication token (convenience function)"""
    return get_authenticator().validate_token(token)


def add_token(token: str) -> bool:
    """Add a new valid token (convenience function)"""
    return get_authenticator().add_token(token)


def remove_token(token: str) -> bool:
    """Remove a token (convenience function)"""
    return get_authenticator().remove_token(token)


def generate_development_token(charger_id: str) -> str:
    """Generate a development token (convenience function)"""
    return get_authenticator().generate_development_token(charger_id)


__all__ = [
    "TokenAuthenticator", 
    "validate_token", 
    "add_token", 
    "remove_token", 
    "generate_development_token",
    "get_authenticator"
]
