"""Tests for security/file_integrity/base_verifier.py."""

import pytest
import tempfile
from pathlib import Path


class TestFileTypeEnum:
    """Tests for FileType enum."""

    def test_faiss_index_value(self):
        """Test FAISS_INDEX enum value."""
        from local_deep_research.security.file_integrity.base_verifier import (
            FileType,
        )

        assert FileType.FAISS_INDEX.value == "faiss_index"

    def test_pdf_value(self):
        """Test PDF enum value."""
        from local_deep_research.security.file_integrity.base_verifier import (
            FileType,
        )

        assert FileType.PDF.value == "pdf"

    def test_export_value(self):
        """Test EXPORT enum value."""
        from local_deep_research.security.file_integrity.base_verifier import (
            FileType,
        )

        assert FileType.EXPORT.value == "export"

    def test_file_type_is_str_enum(self):
        """Test that FileType is a string enum."""
        from local_deep_research.security.file_integrity.base_verifier import (
            FileType,
        )

        assert isinstance(FileType.PDF, str)
        assert FileType.PDF == "pdf"


class TestBaseFileVerifierAbstract:
    """Tests for BaseFileVerifier abstract class."""

    def test_cannot_instantiate_directly(self):
        """Test that BaseFileVerifier cannot be instantiated directly."""
        from local_deep_research.security.file_integrity.base_verifier import (
            BaseFileVerifier,
        )

        with pytest.raises(TypeError, match="abstract"):
            BaseFileVerifier()

    def test_defines_abstract_methods(self):
        """Test that abstract methods are defined."""
        from local_deep_research.security.file_integrity.base_verifier import (
            BaseFileVerifier,
        )

        # Check that the class has the expected abstract methods
        assert hasattr(BaseFileVerifier, "should_verify")
        assert hasattr(BaseFileVerifier, "get_file_type")
        assert hasattr(BaseFileVerifier, "allows_modifications")


class TestConcreteVerifier:
    """Tests using a concrete implementation of BaseFileVerifier."""

    @pytest.fixture
    def concrete_verifier(self):
        """Create a concrete verifier implementation for testing."""
        from local_deep_research.security.file_integrity.base_verifier import (
            BaseFileVerifier,
            FileType,
        )

        class TestVerifier(BaseFileVerifier):
            def should_verify(self, file_path: Path) -> bool:
                return file_path.suffix == ".test"

            def get_file_type(self) -> FileType:
                return FileType.PDF

            def allows_modifications(self) -> bool:
                return False

        return TestVerifier()

    def test_calculate_checksum_returns_sha256_hex(self, concrete_verifier):
        """Test that calculate_checksum returns a SHA256 hex string."""
        with tempfile.NamedTemporaryFile(delete=False, suffix=".test") as f:
            f.write(b"test content")
            f.flush()
            file_path = Path(f.name)

        try:
            checksum = concrete_verifier.calculate_checksum(file_path)

            # SHA256 hex string is 64 characters
            assert len(checksum) == 64
            assert all(c in "0123456789abcdef" for c in checksum)
        finally:
            file_path.unlink()

    def test_calculate_checksum_is_deterministic(self, concrete_verifier):
        """Test that same content produces same checksum."""
        with tempfile.NamedTemporaryFile(delete=False, suffix=".test") as f:
            f.write(b"identical content")
            f.flush()
            file_path = Path(f.name)

        try:
            checksum1 = concrete_verifier.calculate_checksum(file_path)
            checksum2 = concrete_verifier.calculate_checksum(file_path)

            assert checksum1 == checksum2
        finally:
            file_path.unlink()

    def test_calculate_checksum_different_for_different_content(
        self, concrete_verifier
    ):
        """Test that different content produces different checksum."""
        with tempfile.NamedTemporaryFile(delete=False, suffix=".test") as f1:
            f1.write(b"content one")
            f1.flush()
            file_path1 = Path(f1.name)

        with tempfile.NamedTemporaryFile(delete=False, suffix=".test") as f2:
            f2.write(b"content two")
            f2.flush()
            file_path2 = Path(f2.name)

        try:
            checksum1 = concrete_verifier.calculate_checksum(file_path1)
            checksum2 = concrete_verifier.calculate_checksum(file_path2)

            assert checksum1 != checksum2
        finally:
            file_path1.unlink()
            file_path2.unlink()

    def test_calculate_checksum_raises_for_missing_file(
        self, concrete_verifier
    ):
        """Test that FileNotFoundError is raised for missing file."""
        with pytest.raises(FileNotFoundError):
            concrete_verifier.calculate_checksum(Path("/nonexistent/file.test"))

    def test_get_algorithm_returns_sha256(self, concrete_verifier):
        """Test that get_algorithm returns sha256."""
        assert concrete_verifier.get_algorithm() == "sha256"

    def test_should_verify_with_matching_file(self, concrete_verifier):
        """Test should_verify returns True for matching file type."""
        assert (
            concrete_verifier.should_verify(Path("/path/to/file.test")) is True
        )

    def test_should_verify_with_non_matching_file(self, concrete_verifier):
        """Test should_verify returns False for non-matching file type."""
        assert (
            concrete_verifier.should_verify(Path("/path/to/file.txt")) is False
        )

    def test_get_file_type_returns_expected(self, concrete_verifier):
        """Test get_file_type returns the expected FileType."""
        from local_deep_research.security.file_integrity.base_verifier import (
            FileType,
        )

        assert concrete_verifier.get_file_type() == FileType.PDF

    def test_allows_modifications_returns_false(self, concrete_verifier):
        """Test allows_modifications returns False."""
        assert concrete_verifier.allows_modifications() is False


class TestChecksumWithLargeFile:
    """Tests for checksum calculation with larger files."""

    @pytest.fixture
    def verifier(self):
        """Create a concrete verifier for testing."""
        from local_deep_research.security.file_integrity.base_verifier import (
            BaseFileVerifier,
            FileType,
        )

        class LargeFileVerifier(BaseFileVerifier):
            def should_verify(self, file_path: Path) -> bool:
                return True

            def get_file_type(self) -> FileType:
                return FileType.EXPORT

            def allows_modifications(self) -> bool:
                return True

        return LargeFileVerifier()

    def test_handles_file_larger_than_chunk_size(self, verifier):
        """Test that files larger than 4096 bytes are handled correctly."""
        # Create a file larger than the chunk size (4096 bytes)
        content = b"x" * 10000  # 10KB

        with tempfile.NamedTemporaryFile(delete=False) as f:
            f.write(content)
            f.flush()
            file_path = Path(f.name)

        try:
            checksum = verifier.calculate_checksum(file_path)

            # Should still return valid SHA256
            assert len(checksum) == 64
            assert all(c in "0123456789abcdef" for c in checksum)
        finally:
            file_path.unlink()

    def test_empty_file_has_valid_checksum(self, verifier):
        """Test that empty files have a valid checksum."""
        with tempfile.NamedTemporaryFile(delete=False) as f:
            # Don't write anything - empty file
            file_path = Path(f.name)

        try:
            checksum = verifier.calculate_checksum(file_path)

            # Empty file should have the SHA256 of empty string
            # This is the well-known SHA256 hash of "" (not a secret)
            empty_string_sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"  # DevSkim: ignore DS173237
            assert checksum == empty_string_sha256
        finally:
            file_path.unlink()
