"""Tests for hash computation."""

from __future__ import annotations

from pathlib import Path

from paude.hash import compute_config_hash, compute_content_hash


class TestComputeConfigHash:
    """Tests for compute_config_hash."""

    def test_returns_12_chars(self, tmp_path: Path):
        """compute_config_hash returns 12 character hash."""
        entrypoint = tmp_path / "entrypoint.sh"
        entrypoint.write_text("#!/bin/bash\nexec claude")

        result = compute_config_hash(None, None, None, entrypoint, "0.7.0")
        assert len(result) == 12

    def test_same_inputs_same_hash(self, tmp_path: Path):
        """Same inputs produce same hash."""
        config = tmp_path / "paude.json"
        config.write_text('{"base": "python:3.11"}')
        entrypoint = tmp_path / "entrypoint.sh"
        entrypoint.write_text("#!/bin/bash\nexec claude")

        hash1 = compute_config_hash(config, None, "python:3.11", entrypoint, "0.7.0")
        hash2 = compute_config_hash(config, None, "python:3.11", entrypoint, "0.7.0")
        assert hash1 == hash2

    def test_different_inputs_different_hash(self, tmp_path: Path):
        """Different inputs produce different hash."""
        config1 = tmp_path / "config1.json"
        config1.write_text('{"base": "python:3.11"}')
        config2 = tmp_path / "config2.json"
        config2.write_text('{"base": "python:3.12"}')
        entrypoint = tmp_path / "entrypoint.sh"
        entrypoint.write_text("#!/bin/bash\nexec claude")

        hash1 = compute_config_hash(config1, None, "python:3.11", entrypoint, "0.7.0")
        hash2 = compute_config_hash(config2, None, "python:3.12", entrypoint, "0.7.0")
        assert hash1 != hash2

    def test_handles_missing_config_file(self, tmp_path: Path):
        """Handles missing config_file (None)."""
        entrypoint = tmp_path / "entrypoint.sh"
        entrypoint.write_text("#!/bin/bash\nexec claude")

        # Should not raise
        result = compute_config_hash(None, None, None, entrypoint, "0.7.0")
        assert len(result) == 12

    def test_handles_missing_dockerfile(self, tmp_path: Path):
        """Handles missing dockerfile (None)."""
        config = tmp_path / "paude.json"
        config.write_text('{"base": "python:3.11"}')
        entrypoint = tmp_path / "entrypoint.sh"
        entrypoint.write_text("#!/bin/bash\nexec claude")

        # Should not raise
        result = compute_config_hash(config, None, "python:3.11", entrypoint, "0.7.0")
        assert len(result) == 12

    def test_includes_entrypoint_content(self, tmp_path: Path):
        """Hash includes entrypoint content."""
        entrypoint1 = tmp_path / "entrypoint1.sh"
        entrypoint1.write_text("#!/bin/bash\nexec claude")
        entrypoint2 = tmp_path / "entrypoint2.sh"
        entrypoint2.write_text("#!/bin/bash\nexec claude --version")

        hash1 = compute_config_hash(None, None, "python:3.11", entrypoint1, "0.7.0")
        hash2 = compute_config_hash(None, None, "python:3.11", entrypoint2, "0.7.0")
        assert hash1 != hash2

    def test_hash_matches_known_value(self, tmp_path: Path):
        """Verify hash has expected properties for known inputs."""
        config = tmp_path / "paude.json"
        config.write_text('{"base": "python:3.11"}')
        entrypoint = tmp_path / "entrypoint.sh"
        entrypoint.write_text("#!/bin/bash\nexec claude")

        result = compute_config_hash(config, None, "python:3.11", entrypoint, "0.7.0")
        assert len(result) == 12
        assert result.isalnum()

    def test_different_versions_different_hash(self, tmp_path: Path):
        """Different paude versions produce different hashes."""
        config = tmp_path / "paude.json"
        config.write_text('{"base": "python:3.11"}')
        entrypoint = tmp_path / "entrypoint.sh"
        entrypoint.write_text("#!/bin/bash\nexec claude")

        hash1 = compute_config_hash(config, None, "python:3.11", entrypoint, "0.7.0")
        hash2 = compute_config_hash(config, None, "python:3.11", entrypoint, "0.7.1")
        assert hash1 != hash2

    def test_same_version_same_hash(self, tmp_path: Path):
        """Same paude version produces same hash."""
        config = tmp_path / "paude.json"
        config.write_text('{"base": "python:3.11"}')
        entrypoint = tmp_path / "entrypoint.sh"
        entrypoint.write_text("#!/bin/bash\nexec claude")

        hash1 = compute_config_hash(config, None, "python:3.11", entrypoint, "0.7.1")
        hash2 = compute_config_hash(config, None, "python:3.11", entrypoint, "0.7.1")
        assert hash1 == hash2


class TestComputeContentHash:
    """Tests for compute_content_hash."""

    def test_returns_full_hex_digest(self):
        """compute_content_hash returns full 64-char hex digest."""
        result = compute_content_hash(b"test content")
        assert len(result) == 64
        assert all(c in "0123456789abcdef" for c in result)

    def test_same_content_same_hash(self):
        """Same content produces same hash."""
        hash1 = compute_content_hash(b"test content")
        hash2 = compute_content_hash(b"test content")
        assert hash1 == hash2

    def test_different_content_different_hash(self):
        """Different content produces different hash."""
        hash1 = compute_content_hash(b"content a")
        hash2 = compute_content_hash(b"content b")
        assert hash1 != hash2

    def test_multiple_args_combined(self):
        """Multiple arguments are combined into single hash."""
        # Hash of combined should differ from hash of individual pieces
        hash_combined = compute_content_hash(b"abc", b"def")
        hash_single_a = compute_content_hash(b"abc")
        hash_single_b = compute_content_hash(b"def")
        hash_concatenated = compute_content_hash(b"abcdef")

        assert hash_combined != hash_single_a
        assert hash_combined != hash_single_b
        # Combined should equal concatenated since we're just updating the hasher
        assert hash_combined == hash_concatenated

    def test_order_matters(self):
        """Order of arguments affects hash."""
        hash1 = compute_content_hash(b"abc", b"def")
        hash2 = compute_content_hash(b"def", b"abc")
        assert hash1 != hash2
