# [DEF:__tests__/test_llm_provider:Module]
# @RELATION: VERIFIES -> ../llm_provider.py
# @PURPOSE: Contract testing for LLMProviderService and EncryptionManager
# [/DEF:__tests__/test_llm_provider:Module]

import pytest
import os
from unittest.mock import MagicMock
from sqlalchemy.orm import Session
from src.services.llm_provider import EncryptionManager, LLMProviderService
from src.models.llm import LLMProvider
from src.plugins.llm_analysis.models import LLMProviderConfig, ProviderType

# @TEST_CONTRACT: EncryptionManagerModel -> Invariants
# @TEST_INVARIANT: symmetric_encryption
def test_encryption_cycle():
    """Verify encrypted data can be decrypted back to original string."""
    manager = EncryptionManager()
    original = "secret_api_key_123"
    encrypted = manager.encrypt(original)
    assert encrypted != original
    assert manager.decrypt(encrypted) == original

# @TEST_EDGE: empty_string_encryption
def test_empty_string_encryption():
    manager = EncryptionManager()
    original = ""
    encrypted = manager.encrypt(original)
    assert manager.decrypt(encrypted) == ""

# @TEST_EDGE: decrypt_invalid_data
def test_decrypt_invalid_data():
    manager = EncryptionManager()
    with pytest.raises(Exception):
        manager.decrypt("not-encrypted-string")

# @TEST_FIXTURE: mock_db_session
@pytest.fixture
def mock_db():
    return MagicMock(spec=Session)

@pytest.fixture
def service(mock_db):
    return LLMProviderService(db=mock_db)

def test_get_all_providers(service, mock_db):
    service.get_all_providers()
    mock_db.query.assert_called()
    mock_db.query().all.assert_called()

def test_create_provider(service, mock_db):
    config = LLMProviderConfig(
        provider_type=ProviderType.OPENAI,
        name="Test OpenAI",
        base_url="https://api.openai.com",
        api_key="sk-test",
        default_model="gpt-4",
        is_active=True
    )
    
    provider = service.create_provider(config)
    
    mock_db.add.assert_called()
    mock_db.commit.assert_called()
    # Verify API key was encrypted
    assert provider.api_key != "sk-test"
    # Decrypt to verify it matches
    assert EncryptionManager().decrypt(provider.api_key) == "sk-test"

def test_get_decrypted_api_key(service, mock_db):
    # Setup mock provider
    encrypted_key = EncryptionManager().encrypt("secret-value")
    mock_provider = LLMProvider(id="p1", api_key=encrypted_key)
    mock_db.query().filter().first.return_value = mock_provider
    
    key = service.get_decrypted_api_key("p1")
    assert key == "secret-value"

def test_get_decrypted_api_key_not_found(service, mock_db):
    mock_db.query().filter().first.return_value = None
    assert service.get_decrypted_api_key("missing") is None
