"""
Unit tests for PreferencesModule.
"""

from unittest.mock import Mock

import pytest

from helmut4.client.exceptions import Helmut4Error
from helmut4.client.modules.preferences import PreferencesModule


class TestPreferencesModule:
    """Test PreferencesModule functionality."""

    @pytest.fixture
    def mock_client(self):
        """Mock client for testing."""
        client = Mock()
        client.request = Mock()
        return client

    @pytest.fixture
    def preferences_module(self, mock_client):
        """PreferencesModule instance for testing."""
        return PreferencesModule(mock_client)

    # Core Preferences Tests
    def test_get_all(self, preferences_module, mock_client):
        """Test get_all preferences."""
        expected = [
            {
                "id": "pref1",
                "name": "setting1"
            },
            {
                "id": "pref2",
                "name": "setting2"
            },
        ]
        mock_client.request.return_value = expected

        result = preferences_module.get_all()

        assert result == expected
        mock_client.request.assert_called_once_with("GET", "/v1/preferences")

    def test_get_by_tags(self, preferences_module, mock_client):
        """Test get_by_tags with tag list."""
        expected = [{"id": "pref1", "tags": ["important", "system"]}]
        mock_client.request.return_value = expected

        result = preferences_module.get_by_tags(["important", "system"])

        assert result == expected
        mock_client.request.assert_called_once_with(
            "GET", "/v1/preferences/important,system"
        )

    def test_create(self, preferences_module, mock_client):
        """Test create preference."""
        preference_data = {"name": "newpref", "value": "testvalue"}
        expected = {"id": "pref123", **preference_data}
        mock_client.request.return_value = expected

        result = preferences_module.create(preference_data)

        assert result == expected
        mock_client.request.assert_called_once_with(
            "POST", "/v1/preferences", json=preference_data
        )

    def test_update(self, preferences_module, mock_client):
        """Test update preference."""
        preference_data = {
            "id": "pref123",
            "name": "updated",
            "value": "newvalue",
        }
        expected = preference_data
        mock_client.request.return_value = expected

        result = preferences_module.update(preference_data)

        assert result == expected
        mock_client.request.assert_called_once_with(
            "PUT", "/v1/preferences", json=preference_data
        )

    def test_delete(self, preferences_module, mock_client):
        """Test delete preference."""
        mock_client.request.return_value = "Preference deleted"

        result = preferences_module.delete("pref123")

        assert result == "Preference deleted"
        mock_client.request.assert_called_once_with(
            "DELETE", "/v1/preferences/pref123"
        )

    # Storage Management Tests
    def test_get_storage(self, preferences_module, mock_client):
        """Test get_storage method."""
        expected = [
            {
                "id": "storage1",
                "path": "/mnt/storage1"
            },
            {
                "id": "storage2",
                "path": "/mnt/storage2"
            },
        ]
        mock_client.request.return_value = expected

        result = preferences_module.get_storage()

        assert result == expected
        mock_client.request.assert_called_once_with("GET", "/v1/storage")

    def test_add_storage(self, preferences_module, mock_client):
        """Test add_storage method."""
        storage_data = {"path": "/mnt/newstorage", "type": "nfs"}
        expected = {"id": "storage3", **storage_data}
        mock_client.request.return_value = expected

        result = preferences_module.add_storage(storage_data)

        assert result == expected
        mock_client.request.assert_called_once_with(
            "POST", "/v1/storage", json=storage_data
        )

    def test_update_storage(self, preferences_module, mock_client):
        """Test update_storage method."""
        storage_data = {"id": "storage1", "path": "/mnt/updated", "type": "nfs"}
        expected = storage_data
        mock_client.request.return_value = expected

        result = preferences_module.update_storage(storage_data)

        assert result == expected
        mock_client.request.assert_called_once_with(
            "PUT", "/v1/storage", json=storage_data
        )

    def test_delete_storage(self, preferences_module, mock_client):
        """Test delete_storage method."""
        mock_client.request.return_value = "Storage deleted"

        result = preferences_module.delete_storage("storage1")

        assert result == "Storage deleted"
        mock_client.request.assert_called_once_with(
            "DELETE", "/v1/storage/storage1"
        )

    # Active Directory Tests
    def test_get_active_directory(self, preferences_module, mock_client):
        """Test get_active_directory method."""
        expected = {
            "enabled": True,
            "domain": "example.com",
            "server": "dc.example.com",
        }
        mock_client.request.return_value = expected

        result = preferences_module.get_active_directory()

        assert result == expected
        mock_client.request.assert_called_once_with(
            "GET", "/v1/activedirectory"
        )

    def test_update_active_directory(self, preferences_module, mock_client):
        """Test update_active_directory method."""
        ad_config = {
            "enabled": True,
            "domain": "example.com",
            "server": "dc.example.com",
        }
        expected = ad_config
        mock_client.request.return_value = expected

        result = preferences_module.update_active_directory(ad_config)

        assert result == expected
        mock_client.request.assert_called_once_with(
            "PUT", "/v1/activedirectory", json=ad_config
        )

    # Backup/Restore/Test Tests
    def test_create_backup(self, preferences_module, mock_client):
        """Test create_backup method."""
        mock_client.request.return_value = b"backup_binary_data"

        result = preferences_module.create_backup(["helmut", "metadata"])

        assert result == b"backup_binary_data"
        mock_client.request.assert_called_once_with(
            "GET", "/v1/backup/helmut,metadata"
        )

    def test_restore_backup(self, preferences_module, mock_client):
        """Test restore_backup with file upload."""
        mock_file = Mock()
        expected = {"status": "restored", "timestamp": "2026-01-27T12:00:00Z"}
        mock_client.request.return_value = expected

        result = preferences_module.restore_backup(mock_file)

        assert result == expected
        mock_client.request.assert_called_once_with(
            "POST", "/v1/restore", files={"file": mock_file}
        )

    def test_test_module(self, preferences_module, mock_client):
        """Test test_module method."""
        mock_client.request.return_value = 42

        result = preferences_module.test_module("FLOW")

        assert result == 42
        mock_client.request.assert_called_once_with(
            "GET", "/v1/preferences/test/FLOW"
        )

    # Encryption Tests
    def test_encrypt_success(self, preferences_module, mock_client):
        """Test encrypt method with successful encryption."""
        mock_client.request.return_value = {"result": "encrypted_abc123xyz"}

        result = preferences_module.encrypt("my_secret_password")

        assert result == {"result": "encrypted_abc123xyz"}
        mock_client.request.assert_called_once_with(
            "POST",
            "/v1/encryption/encrypt",
            json={"key": "my_secret_password"},
        )

    def test_encrypt_empty_string(self, preferences_module, mock_client):
        """Test encrypt with empty string edge case."""
        mock_client.request.return_value = {"result": ""}

        result = preferences_module.encrypt("")

        assert result == {"result": ""}
        mock_client.request.assert_called_once_with(
            "POST", "/v1/encryption/encrypt", json={"key": ""}
        )

    def test_decrypt_success(self, preferences_module, mock_client):
        """Test decrypt method with successful decryption."""
        mock_client.request.return_value = {"result": "my_secret_password"}

        result = preferences_module.decrypt("encrypted_abc123xyz")

        assert result == {"result": "my_secret_password"}
        mock_client.request.assert_called_once_with(
            "POST",
            "/v1/encryption/decrypt",
            json={"key": "encrypted_abc123xyz"},
        )

    def test_decrypt_invalid_key(self, preferences_module, mock_client):
        """Test decrypt with invalid key raises Helmut4Error."""
        error = Helmut4Error("Decryption failed", status_code=500, response={})
        mock_client.request.side_effect = error

        with pytest.raises(Helmut4Error) as exc_info:
            preferences_module.decrypt("invalid_key")

        assert exc_info.value.status_code == 500
