"""Unit tests for file integrity verification."""

import pytest

from src.infrastructure.security.file_integrity import (
    FileIntegrityManager,
    get_integrity_manager,
)


class TestFileIntegrityManager:
    """Test the FileIntegrityManager class."""

    def test_calculate_checksum(self, tmp_path):
        """Test checksum calculation for a file."""
        # Create a test file
        test_file = tmp_path / "test.txt"
        test_file.write_text("Hello, World!")

        # Create integrity manager with temp checksum file
        checksum_file = tmp_path / "checksums.json"
        manager = FileIntegrityManager(checksum_file)

        # Calculate checksum
        checksum = manager.calculate_checksum(test_file)

        # Verify checksum is a hex string
        assert isinstance(checksum, str)
        assert len(checksum) == 64  # SHA256 produces 64 hex chars
        assert all(c in "0123456789abcdef" for c in checksum)

    def test_calculate_checksum_nonexistent_file(self, tmp_path):
        """Test checksum calculation for nonexistent file."""
        nonexistent = tmp_path / "nonexistent.txt"
        checksum_file = tmp_path / "checksums.json"
        manager = FileIntegrityManager(checksum_file)

        with pytest.raises(FileNotFoundError):
            manager.calculate_checksum(nonexistent)

    def test_store_and_verify_checksum(self, tmp_path):
        """Test storing and verifying checksum."""
        # Create test file
        test_file = tmp_path / "test.txt"
        test_file.write_text("Test content")

        checksum_file = tmp_path / "checksums.json"
        manager = FileIntegrityManager(checksum_file)

        # Store checksum
        stored_checksum = manager.store_checksum(test_file)
        assert isinstance(stored_checksum, str)

        # Verify checksum
        assert manager.verify_checksum(test_file)

    def test_verify_checksum_modified_file(self, tmp_path):
        """Test checksum verification fails for modified file."""
        # Create test file
        test_file = tmp_path / "test.txt"
        test_file.write_text("Original content")

        checksum_file = tmp_path / "checksums.json"
        manager = FileIntegrityManager(checksum_file)

        # Store checksum
        manager.store_checksum(test_file)

        # Modify file
        test_file.write_text("Modified content")

        # Verification should fail
        assert not manager.verify_checksum(test_file)

    def test_verify_checksum_with_expected_value(self, tmp_path):
        """Test checksum verification with expected value."""
        test_file = tmp_path / "test.txt"
        test_file.write_text("Known content")

        checksum_file = tmp_path / "checksums.json"
        manager = FileIntegrityManager(checksum_file)

        # Calculate known checksum
        expected = manager.calculate_checksum(test_file)

        # Verify with expected checksum
        assert manager.verify_checksum(test_file, expected)

        # Verify with wrong checksum
        wrong_checksum = "a" * 64
        assert not manager.verify_checksum(test_file, wrong_checksum)

    def test_has_checksum(self, tmp_path):
        """Test checking if checksum exists."""
        test_file = tmp_path / "test.txt"
        test_file.write_text("Content")

        checksum_file = tmp_path / "checksums.json"
        manager = FileIntegrityManager(checksum_file)

        # Initially no checksum
        assert not manager.has_checksum(test_file)

        # Store checksum
        manager.store_checksum(test_file)

        # Now has checksum
        assert manager.has_checksum(test_file)

    def test_remove_checksum(self, tmp_path):
        """Test removing checksum."""
        test_file = tmp_path / "test.txt"
        test_file.write_text("Content")

        checksum_file = tmp_path / "checksums.json"
        manager = FileIntegrityManager(checksum_file)

        # Store checksum
        manager.store_checksum(test_file)
        assert manager.has_checksum(test_file)

        # Remove checksum
        result = manager.remove_checksum(test_file)
        assert result is True
        assert not manager.has_checksum(test_file)

        # Try to remove again
        result = manager.remove_checksum(test_file)
        assert result is False

    def test_persistence(self, tmp_path):
        """Test that checksums persist across instances."""
        test_file = tmp_path / "test.txt"
        test_file.write_text("Persistent content")

        checksum_file = tmp_path / "checksums.json"

        # Store checksum in first instance
        manager1 = FileIntegrityManager(checksum_file)
        manager1.store_checksum(test_file)

        # Load in second instance
        manager2 = FileIntegrityManager(checksum_file)
        assert manager2.has_checksum(test_file)
        assert manager2.verify_checksum(test_file)

    def test_get_integrity_manager_singleton(self):
        """Test that get_integrity_manager returns singleton."""
        manager1 = get_integrity_manager()
        manager2 = get_integrity_manager()

        assert manager1 is manager2

    def test_checksum_file_created_automatically(self, tmp_path):
        """Test that checksum file is created in data directory."""
        test_file = tmp_path / "test.txt"
        test_file.write_text("Content")

        checksum_file = tmp_path / "checksums.json"
        manager = FileIntegrityManager(checksum_file)

        # Store checksum
        manager.store_checksum(test_file)

        # Verify checksum file was created
        assert checksum_file.exists()

    def test_unsupported_algorithm(self, tmp_path):
        """Test that unsupported hash algorithm raises error."""
        test_file = tmp_path / "test.txt"
        test_file.write_text("Content")

        checksum_file = tmp_path / "checksums.json"
        manager = FileIntegrityManager(checksum_file)

        with pytest.raises(ValueError, match="Unsupported hash algorithm"):
            manager.calculate_checksum(test_file, algorithm="invalid")

    def test_corrupted_checksum_file(self, tmp_path):
        """Test handling of corrupted checksum file."""
        test_file = tmp_path / "test.txt"
        test_file.write_text("Content")

        checksum_file = tmp_path / "checksums.json"

        # Create corrupted checksum file
        checksum_file.write_text("{ invalid json")

        # Manager should handle gracefully
        manager = FileIntegrityManager(checksum_file)
        assert manager.checksums == {}

        # Should be able to store new checksum
        manager.store_checksum(test_file)
        assert manager.has_checksum(test_file)

    def test_verify_checksum_no_stored_checksum(self, tmp_path):
        """Test verification when no checksum is stored."""
        test_file = tmp_path / "test.txt"
        test_file.write_text("Content")

        checksum_file = tmp_path / "checksums.json"
        manager = FileIntegrityManager(checksum_file)

        # Verification should return False
        assert not manager.verify_checksum(test_file)
