"""
API Key Service.

This module handles API key generation, validation, and management.
"""

import secrets
import hashlib
from typing import Optional
from datetime import datetime
from sqlalchemy.orm import Session

from app.models.api_key import ApiKey
from app.models.user import User


class ApiKeyService:
    """Service for managing API keys."""
    
    def __init__(self, db: Session):
        self.db = db
    
    def generate_api_key(self, user_id: int, rate_limit: int = 100) -> ApiKey:
        """
        Generate a new API key for a user.
        
        Args:
            user_id: ID of the user
            rate_limit: Rate limit per minute (default: 100)
        
        Returns:
            Created ApiKey object
        
        Raises:
            ValueError: If user doesn't exist
        """
        # Verify user exists
        user = self.db.query(User).filter(User.id == user_id).first()
        if not user:
            raise ValueError(f"User with id {user_id} not found")
        
        # Generate API key (32 bytes = 256 bits)
        api_key = secrets.token_urlsafe(32)
        
        # Hash the API key for storage (SHA-256)
        key_hash = hashlib.sha256(api_key.encode()).hexdigest()
        
        # Store prefix for identification (first 8 characters)
        key_prefix = api_key[:8]
        
        # Create API key record
        api_key_record = ApiKey(
            user_id=user_id,
            key_hash=key_hash,
            key_prefix=key_prefix,
            rate_limit=rate_limit,
            is_active=True,
            created_at=datetime.utcnow()
        )
        
        self.db.add(api_key_record)
        self.db.commit()
        self.db.refresh(api_key_record)
        
        # Return the plain API key (only time it's shown)
        # We'll add it to the dict temporarily for the response
        api_key_dict = api_key_record.to_dict()
        api_key_dict['api_key'] = api_key
        
        return api_key_dict
    
    def validate_api_key(self, api_key: str) -> Optional[ApiKey]:
        """
        Validate an API key.
        
        Args:
            api_key: The API key to validate
        
        Returns:
            ApiKey object if valid, None otherwise
        """
        # Hash the provided API key
        key_hash = hashlib.sha256(api_key.encode()).hexdigest()
        
        # Query for matching hash
        api_key_record = self.db.query(ApiKey).filter(
            ApiKey.key_hash == key_hash,
            ApiKey.is_active == True
        ).first()
        
        if api_key_record:
            # Update last used timestamp
            api_key_record.last_used_at = datetime.utcnow()
            self.db.commit()
            self.db.refresh(api_key_record)
            return api_key_record
        
        return None
    
    def get_user_api_keys(self, user_id: int) -> list[dict]:
        """
        Get all API keys for a user.
        
        Args:
            user_id: ID of the user
        
        Returns:
            List of API key dictionaries (without actual keys)
        """
        api_keys = self.db.query(ApiKey).filter(
            ApiKey.user_id == user_id
        ).all()
        
        return [api_key.to_dict() for api_key in api_keys]
    
    def revoke_api_key(self, api_key_id: int, user_id: int) -> bool:
        """
        Revoke (deactivate) an API key.
        
        Args:
            api_key_id: ID of the API key to revoke
            user_id: ID of the user (for authorization)
        
        Returns:
            True if revoked, False otherwise
        """
        api_key = self.db.query(ApiKey).filter(
            ApiKey.id == api_key_id,
            ApiKey.user_id == user_id
        ).first()
        
        if api_key:
            api_key.is_active = False
            self.db.commit()
            return True
        
        return False
    
    def regenerate_api_key(self, api_key_id: int, user_id: int) -> Optional[dict]:
        """
        Regenerate an API key (create new, deactivate old).
        
        Args:
            api_key_id: ID of the API key to regenerate
            user_id: ID of the user (for authorization)
        
        Returns:
            New API key dict with plain key, or None if not found
        """
        old_api_key = self.db.query(ApiKey).filter(
            ApiKey.id == api_key_id,
            ApiKey.user_id == user_id
        ).first()
        
        if not old_api_key:
            return None
        
        # Get rate limit from old key
        rate_limit = old_api_key.rate_limit
        
        # Deactivate old key
        old_api_key.is_active = False
        self.db.commit()
        
        # Generate new key
        return self.generate_api_key(user_id, rate_limit)
