"""
Tests for API Key Service.

This module tests the API key generation, validation, and management.
"""

import pytest
from sqlalchemy.orm import Session

from app.services.apiKeyService import ApiKeyService
from app.models.api_key import ApiKey
from app.models.user import User


@pytest.fixture
def sample_user(db: Session):
    """Create a sample user for testing."""
    user = User(
        email="test@example.com",
        name="Test User",
        is_premium=False
    )
    db.add(user)
    db.commit()
    db.refresh(user)
    return user


class TestApiKeyGeneration:
    """Tests for API key generation."""

    def test_generate_api_key_success(self, db: Session, sample_user: User):
        """Test successful API key generation."""
        service = ApiKeyService(db)
        result = service.generate_api_key(sample_user.id, rate_limit=100)

        assert "api_key" in result
        assert "id" in result
        assert "key_prefix" in result
        assert "user_id" in result
        assert result["user_id"] == sample_user.id
        assert result["rate_limit"] == 100
        assert result["is_active"] == True
        assert len(result["api_key"]) > 0
        assert len(result["key_prefix"]) == 8

    def test_generate_api_key_invalid_user(self, db: Session):
        """Test API key generation with invalid user ID."""
        service = ApiKeyService(db)
        
        with pytest.raises(ValueError) as exc_info:
            service.generate_api_key(99999)
        
        assert "not found" in str(exc_info.value).lower()

    def test_generate_api_key_stores_hash(self, db: Session, sample_user: User):
        """Test that API key stores hash instead of plain key."""
        service = ApiKeyService(db)
        result = service.generate_api_key(sample_user.id)

        # Query the database to verify hash is stored
        api_key_record = db.query(ApiKey).filter(
            ApiKey.id == result["id"]
        ).first()

        assert api_key_record is not None
        assert api_key_record.key_hash != result["api_key"]
        assert len(api_key_record.key_hash) == 64  # SHA-256 hash length
        assert api_key_record.key_prefix == result["api_key"][:8]


class TestApiKeyValidation:
    """Tests for API key validation."""

    def test_validate_api_key_success(self, db: Session, sample_user: User):
        """Test successful API key validation."""
        service = ApiKeyService(db)
        result = service.generate_api_key(sample_user.id)
        plain_api_key = result["api_key"]

        # Validate the key
        validated = service.validate_api_key(plain_api_key)

        assert validated is not None
        assert validated.user_id == sample_user.id
        assert validated.is_active == True

    def test_validate_api_key_invalid(self, db: Session):
        """Test validation with invalid API key."""
        service = ApiKeyService(db)
        validated = service.validate_api_key("invalid_key_12345")

        assert validated is None

    def test_validate_api_key_updates_last_used(self, db: Session, sample_user: User):
        """Test that validation updates last_used_at timestamp."""
        service = ApiKeyService(db)
        result = service.generate_api_key(sample_user.id)
        plain_api_key = result["api_key"]

        # Validate the key
        validated = service.validate_api_key(plain_api_key)

        assert validated.last_used_at is not None

    def test_validate_api_key_inactive(self, db: Session, sample_user: User):
        """Test validation with inactive API key."""
        service = ApiKeyService(db)
        result = service.generate_api_key(sample_user.id)
        plain_api_key = result["api_key"]

        # Deactivate the key
        api_key_record = db.query(ApiKey).filter(
            ApiKey.id == result["id"]
        ).first()
        api_key_record.is_active = False
        db.commit()

        # Try to validate
        validated = service.validate_api_key(plain_api_key)

        assert validated is None


class TestApiKeyManagement:
    """Tests for API key management."""

    def test_get_user_api_keys(self, db: Session, sample_user: User):
        """Test retrieving all API keys for a user."""
        service = ApiKeyService(db)

        # Generate 3 keys
        keys = []
        for i in range(3):
            result = service.generate_api_key(sample_user.id)
            keys.append(result)

        # Retrieve all keys
        user_keys = service.get_user_api_keys(sample_user.id)

        assert len(user_keys) == 3
        # Verify plain keys are not included
        for key in user_keys:
            assert "api_key" not in key
            assert "key_prefix" in key

    def test_revoke_api_key_success(self, db: Session, sample_user: User):
        """Test successful API key revocation."""
        service = ApiKeyService(db)
        result = service.generate_api_key(sample_user.id)
        api_key_id = result["id"]

        # Revoke the key
        revoked = service.revoke_api_key(api_key_id, sample_user.id)

        assert revoked is True

        # Verify it's deactivated
        api_key_record = db.query(ApiKey).filter(
            ApiKey.id == api_key_id
        ).first()
        assert api_key_record.is_active == False

    def test_revoke_api_key_wrong_user(self, db: Session, sample_user: User):
        """Test revoking key with wrong user ID."""
        service = ApiKeyService(db)
        result = service.generate_api_key(sample_user.id)
        api_key_id = result["id"]

        # Try to revoke with wrong user ID
        revoked = service.revoke_api_key(api_key_id, 99999)

        assert revoked is False

    def test_regenerate_api_key_success(self, db: Session, sample_user: User):
        """Test successful API key regeneration."""
        service = ApiKeyService(db)
        old_result = service.generate_api_key(sample_user.id)
        old_api_key_id = old_result["id"]

        # Regenerate
        new_result = service.regenerate_api_key(old_api_key_id, sample_user.id)

        assert new_result is not None
        assert "api_key" in new_result
        assert new_result["api_key"] != old_result["api_key"]
        assert new_result["id"] != old_api_key_id

        # Verify old key is deactivated
        old_key_record = db.query(ApiKey).filter(
            ApiKey.id == old_api_key_id
        ).first()
        assert old_key_record.is_active == False

    def test_regenerate_api_key_wrong_user(self, db: Session, sample_user: User):
        """Test regenerating key with wrong user ID."""
        service = ApiKeyService(db)
        old_result = service.generate_api_key(sample_user.id)

        # Try to regenerate with wrong user ID
        new_result = service.regenerate_api_key(old_result["id"], 99999)

        assert new_result is None
