import pytest
from unittest.mock import MagicMock, patch
from azure.core.exceptions import ResourceExistsError, ResourceNotFoundError
from aleph_secrets_manager.src.azure_keyvault_adaptor import AzureSecretsManager
from aleph_secrets_manager.src.port import Secret


@pytest.fixture
def mock_client():
    return MagicMock()


@pytest.fixture
def secrets_manager(mock_client):
    return AzureSecretsManager(mock_client)


def test_write_secret_success(secrets_manager, mock_client):
    secret = Secret(key="test_key", value="test_value")
    secrets_manager.write_secret(secret)
    mock_client.set_secret.assert_called_with("test-key", "test_value")


def test_write_secret_recover_deleted(secrets_manager, mock_client):
    secret = Secret(key="test_key", value="test_value")
    mock_client.set_secret.side_effect = [ResourceExistsError('"code": "ObjectIsDeletedButRecoverable"'), None]
    mock_client.begin_recover_deleted_secret.return_value = MagicMock()
    with patch("aleph_secrets_manager.src.azure_keyvault_adaptor.sleep") as mock_sleep:
        secrets_manager.write_secret(secret)
        mock_client.begin_recover_deleted_secret.assert_called_with("test-key")
        mock_sleep.assert_called()
        assert mock_client.set_secret.call_count == 2


def test_write_secret_other_exception(secrets_manager, mock_client):
    secret = Secret(key="test_key", value="test_value")
    mock_client.set_secret.side_effect = Exception("fail")
    with pytest.raises(Exception):
        secrets_manager.write_secret(secret)


def test_read_secret_success(secrets_manager, mock_client):
    mock_secret = MagicMock()
    mock_secret.name = "test-key"
    mock_secret.value = "test_value"
    mock_client.get_secret.return_value = mock_secret
    result = secrets_manager.read_secret("test_key")
    assert result.key == "test_key"
    assert result.value == "test_value"


def test_read_secret_not_found(secrets_manager, mock_client):
    mock_client.get_secret.side_effect = ResourceNotFoundError("not found")
    with pytest.raises(ValueError):
        secrets_manager.read_secret("test_key")


def test_delete_secret_success(secrets_manager, mock_client):
    poller = MagicMock()
    mock_client.begin_delete_secret.return_value = poller
    poller.result.return_value = None
    secrets_manager.delete_secret("test_key")
    mock_client.begin_delete_secret.assert_called_with("test-key")
    poller.result.assert_called()


def test_list_all_secrets(secrets_manager, mock_client):
    secret_property_1 = MagicMock()
    secret_property_1.name = 'test-key'
    secret_property_2 = MagicMock()
    secret_property_2.name = 'another-key'
    mock_secret_props = [secret_property_1, secret_property_2]
    mock_client.list_properties_of_secrets.return_value = mock_secret_props
    result = secrets_manager.list_all_secrets()
    assert result == ["test_key", "another_key"]


def test_read_all_secrets(secrets_manager, mock_client):
    secrets_manager.list_all_secrets = MagicMock(return_value=["test_key"])  # patch method
    secrets_manager.read_secret = MagicMock(return_value=Secret(key="test_key", value="val"))
    result = secrets_manager.read_all_secrets()
    assert result == [Secret(key="test_key", value="val")]
