"""
Tests for the C implementation of kHeavyHash.

These tests verify that the C implementation produces correct results
and matches the expected behavior. Tests follow FIRST principles:
- Fast: No external dependencies, deterministic inputs
- Independent: Each test is isolated
- Repeatable: Same inputs always produce same outputs
- Self-Validating: Clear pass/fail assertions
- Timely: Tests written alongside implementation
"""

import pytest

# Import test vectors
# Mypy sees redefinitions here due to try/except fallback pattern - this is intentional
try:
    from tests.test_vectors import (  # type: ignore[no-redef]
        TEST_VECTOR_1_NONCE,
        TEST_VECTOR_1_PRE_POW_HASH,
        TEST_VECTOR_1_TIMESTAMP,
        TEST_VECTORS,
        make_pre_pow_hash_from_bytes,
    )
except ImportError:
    try:
        from test_vectors import (  # type: ignore[no-redef]
            TEST_VECTOR_1_NONCE,
            TEST_VECTOR_1_PRE_POW_HASH,
            TEST_VECTOR_1_TIMESTAMP,
            TEST_VECTORS,
            make_pre_pow_hash_from_bytes,
        )
    except ImportError:
        # Fallback values if test_vectors not available
        # These are intentionally redefined as fallbacks - ignore mypy warnings
        TEST_VECTORS = []  # type: ignore[no-redef]
        TEST_VECTOR_1_PRE_POW_HASH = bytes.fromhex(  # type: ignore[no-redef]
            "0ad86e9bef09726cdc75913e44ec96521391c7ceb2aae3c633f46a94bf4d2546"
        )
        TEST_VECTOR_1_TIMESTAMP = bytes.fromhex("3e6bd36895010000")  # type: ignore[no-redef]
        TEST_VECTOR_1_NONCE = bytes.fromhex("39fd069384065157")  # type: ignore[no-redef]
        import hashlib

        def make_pre_pow_hash_from_bytes(data: bytes) -> bytes:  # type: ignore[no-redef]
            first_hash = hashlib.sha256(data).digest()
            return hashlib.sha256(first_hash).digest()


class TestCImplementation:
    """Test the C implementation directly."""

    def test_c_extension_available(self):
        """Test that the C extension can be imported."""
        try:
            from kheavyhash._c_ext import kheavyhash as c_kheavyhash

            assert callable(c_kheavyhash)
        except ImportError:
            pytest.skip("C extension not available (this is OK, will use Python fallback)")

    def test_c_extension_basic_functionality(self):
        """Test basic functionality of C extension."""
        try:
            from kheavyhash._c_ext import kheavyhash as c_kheavyhash
        except ImportError:
            pytest.skip("C extension not available")

        # Test with values from first test vector
        padding = bytes(32)
        nonce = bytes(8)
        test_input = TEST_VECTOR_1_PRE_POW_HASH + TEST_VECTOR_1_TIMESTAMP + padding + nonce

        result = c_kheavyhash(test_input)
        assert len(result) == 32
        assert isinstance(result, bytes)

        # Test with pattern
        pre_pow_hash2 = bytes(range(32))
        timestamp2 = TEST_VECTOR_1_TIMESTAMP
        test_input2 = pre_pow_hash2 + timestamp2 + padding + nonce
        result2 = c_kheavyhash(test_input2)
        assert len(result2) == 32
        assert result2 != result  # Different inputs should produce different outputs

    def test_c_extension_deterministic(self):
        """Test that C extension produces deterministic results."""
        try:
            from kheavyhash._c_ext import kheavyhash as c_kheavyhash
        except ImportError:
            pytest.skip("C extension not available")

        padding = bytes(32)
        nonce = bytes(8)
        test_input = TEST_VECTOR_1_PRE_POW_HASH + TEST_VECTOR_1_TIMESTAMP + padding + nonce
        result1 = c_kheavyhash(test_input)
        result2 = c_kheavyhash(test_input)
        assert result1 == result2, "C implementation should be deterministic"

    def test_c_extension_input_validation(self):
        """Test that C extension validates input length."""
        try:
            from kheavyhash._c_ext import kheavyhash as c_kheavyhash
        except ImportError:
            pytest.skip("C extension not available")

        # Too short
        with pytest.raises(ValueError, match="exactly 80 bytes"):
            c_kheavyhash(bytes(79))

        # Too long
        with pytest.raises(ValueError, match="exactly 80 bytes"):
            c_kheavyhash(bytes(81))

    @pytest.mark.parametrize(
        "input_hex,expected_hex", [(tv[0], tv[1]) for tv in TEST_VECTORS if tv[1] is not None]
    )
    def test_c_extension_test_vectors(self, input_hex, expected_hex):
        """Test C extension against known test vectors."""
        try:
            from kheavyhash._c_ext import kheavyhash as c_kheavyhash
        except ImportError:
            pytest.skip("C extension not available")

        if expected_hex is None:
            pytest.skip("Test vector not yet populated")

        work_order = bytes.fromhex(input_hex)
        assert len(work_order) == 80

        result = c_kheavyhash(work_order)
        expected = bytes.fromhex(expected_hex)

        assert len(result) == 32
        assert len(expected) == 32
        assert result == expected, (
            f"C implementation output mismatch!\n"
            f"Input:    {input_hex}\n"
            f"Expected: {expected_hex}\n"
            f"Got:      {result.hex()}\n"
        )


class TestImplementationConsistency:
    """Test that C and Python implementations produce same results."""

    def test_implementations_consistent_basic(self):
        """Test that both implementations produce same results for basic inputs."""
        try:
            from kheavyhash._c_ext import kheavyhash as c_kheavyhash

            from kheavyhash.kheavyhash_python import kheavyhash as python_kheavyhash
        except ImportError:
            pytest.skip("C extension not available, cannot compare")

        # Use values from first test vector
        padding = bytes(32)
        nonce = bytes(8)
        test_input1 = TEST_VECTOR_1_PRE_POW_HASH + TEST_VECTOR_1_TIMESTAMP + padding + nonce

        # Additional test cases with different pre_pow_hash values
        pre_pow_hash2 = bytes(range(32))
        test_input2 = pre_pow_hash2 + TEST_VECTOR_1_TIMESTAMP + padding + nonce

        # All ones
        pre_pow_hash3 = bytes([0xFF] * 32)
        test_input3 = pre_pow_hash3 + TEST_VECTOR_1_TIMESTAMP + padding + nonce

        test_cases = [
            test_input1,  # Known good test vector values
            test_input2,  # Pattern with known good timestamp
            test_input3,  # All ones with known good timestamp
        ]

        for test_input in test_cases:
            c_result = c_kheavyhash(test_input)
            python_result = python_kheavyhash(test_input)
            assert c_result == python_result, (
                f"Implementations differ for input: {test_input.hex()[:32]}...\n"
                f"C:      {c_result.hex()}\n"
                f"Python: {python_result.hex()}"
            )

    @pytest.mark.parametrize("input_hex", [tv[0] for tv in TEST_VECTORS])
    def test_implementations_consistent_vectors(self, input_hex):
        """Test that both implementations produce same results for test vectors."""
        try:
            from kheavyhash._c_ext import kheavyhash as c_kheavyhash

            from kheavyhash.kheavyhash_python import kheavyhash as python_kheavyhash
        except ImportError:
            pytest.skip("C extension not available, cannot compare")

        work_order = bytes.fromhex(input_hex)
        assert len(work_order) == 80

        c_result = c_kheavyhash(work_order)
        python_result = python_kheavyhash(work_order)

        assert c_result == python_result, (
            f"Implementations differ for test vector: {input_hex[:32]}...\n"
            f"C:      {c_result.hex()}\n"
            f"Python: {python_result.hex()}"
        )


class TestFallbackMechanism:
    """Test the automatic fallback mechanism."""

    def test_main_import_uses_c_if_available(self):
        """Test that main import prefers C extension."""
        # This test verifies the fallback logic in __init__.py
        from kheavyhash import kheavyhash

        padding = bytes(32)
        nonce = bytes(8)
        test_input = TEST_VECTOR_1_PRE_POW_HASH + TEST_VECTOR_1_TIMESTAMP + padding + nonce
        result = kheavyhash(test_input)
        assert len(result) == 32

    def test_fallback_to_native_when_c_unavailable(self):
        """Test that fallback to native works when C extension unavailable."""
        # This is tested implicitly - if C extension fails to import,
        # the package should still work with Python implementation
        from kheavyhash import kheavyhash

        padding = bytes(32)
        nonce = bytes(8)
        test_input = TEST_VECTOR_1_PRE_POW_HASH + TEST_VECTOR_1_TIMESTAMP + padding + nonce
        result = kheavyhash(test_input)
        assert len(result) == 32
