"""
Test scenarios for AssetRegistry JSON persistence functionality.

This module tests the AssetRegistry class for Issue #142: Phase 1 - Core Asset Management Module.
Tests cover JSON-based metadata persistence, SHA-256 content hashing, MIME type detection,
and thread-safe registry operations.

Requirements:
- JSON-based asset metadata persistence
- SHA-256 content hashing for deduplication
- MIME type detection and file size tracking
- Thread-safe registry operations
"""

import json
import os
import tempfile
import threading
import time
from pathlib import Path
from unittest.mock import Mock, patch
import pytest

from markitect.assets.registry import AssetRegistry
from markitect.assets.exceptions import AssetError, RegistryError


class TestAssetRegistryCore:
    """Core functionality tests for AssetRegistry."""

    def test_registry_initialization(self):
        """Test AssetRegistry can be initialized with registry path."""
        with tempfile.TemporaryDirectory() as temp_dir:
            registry_path = Path(temp_dir) / "test_registry.json"
            registry = AssetRegistry(registry_path)

            assert registry.registry_path == registry_path
            assert registry_path.exists()  # Should create empty registry

    def test_registry_loads_existing_json(self):
        """Test AssetRegistry loads existing JSON registry file."""
        with tempfile.TemporaryDirectory() as temp_dir:
            registry_path = Path(temp_dir) / "existing_registry.json"

            # Create existing registry with test data
            test_data = {
                "assets": {
                    "hash123": {
                        "path": "/test/file.txt",
                        "content_hash": "hash123",
                        "mime_type": "text/plain",
                        "size": 100
                    }
                }
            }
            registry_path.write_text(json.dumps(test_data))

            registry = AssetRegistry(registry_path)
            assets = registry.list_assets()

            assert len(assets) == 1
            assert assets[0]["content_hash"] == "hash123"


class TestAssetRegistryHashing:
    """Test SHA-256 content hashing functionality."""

    def test_generate_content_hash_from_file(self):
        """Test generating SHA-256 hash from file content."""
        with tempfile.TemporaryDirectory() as temp_dir:
            registry_path = Path(temp_dir) / "registry.json"
            test_file = Path(temp_dir) / "test.txt"
            test_file.write_text("Hello, World!")

            registry = AssetRegistry(registry_path)
            content_hash = registry.generate_content_hash(test_file)

            # SHA-256 of "Hello, World!" should be consistent
            expected_hash = "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f"
            assert content_hash == expected_hash

    def test_generate_content_hash_from_bytes(self):
        """Test generating SHA-256 hash from byte content."""
        with tempfile.TemporaryDirectory() as temp_dir:
            registry_path = Path(temp_dir) / "registry.json"
            registry = AssetRegistry(registry_path)

            test_content = b"Binary content test"
            content_hash = registry.generate_content_hash(test_content)

            # Should generate consistent hash for same content
            assert len(content_hash) == 64  # SHA-256 hex length
            assert isinstance(content_hash, str)


class TestAssetRegistryMimeTypes:
    """Test MIME type detection functionality."""

    def test_detect_mime_type_text_file(self):
        """Test MIME type detection for text files."""
        with tempfile.TemporaryDirectory() as temp_dir:
            registry_path = Path(temp_dir) / "registry.json"
            test_file = Path(temp_dir) / "test.txt"
            test_file.write_text("Plain text content")

            registry = AssetRegistry(registry_path)
            mime_type = registry.detect_mime_type(test_file)

            assert mime_type.startswith("text/")

    def test_detect_mime_type_image_file(self):
        """Test MIME type detection for image files."""
        with tempfile.TemporaryDirectory() as temp_dir:
            registry_path = Path(temp_dir) / "registry.json"
            # Create minimal PNG file (8-byte PNG signature + IHDR)
            png_data = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR'
            test_file = Path(temp_dir) / "test.png"
            test_file.write_bytes(png_data)

            registry = AssetRegistry(registry_path)
            mime_type = registry.detect_mime_type(test_file)

            assert mime_type == "image/png"


class TestAssetRegistryOperations:
    """Test asset registration and retrieval operations."""

    def test_register_asset(self):
        """Test registering a new asset in the registry."""
        with tempfile.TemporaryDirectory() as temp_dir:
            registry_path = Path(temp_dir) / "registry.json"
            test_file = Path(temp_dir) / "asset.txt"
            test_file.write_text("Test asset content")

            registry = AssetRegistry(registry_path)
            asset_info = registry.register_asset(test_file)

            assert "content_hash" in asset_info
            assert "mime_type" in asset_info
            assert "size" in asset_info
            assert asset_info["path"] == str(test_file)

    def test_get_asset_by_hash(self):
        """Test retrieving asset information by content hash."""
        with tempfile.TemporaryDirectory() as temp_dir:
            registry_path = Path(temp_dir) / "registry.json"
            test_file = Path(temp_dir) / "asset.txt"
            test_file.write_text("Test content for retrieval")

            registry = AssetRegistry(registry_path)
            asset_info = registry.register_asset(test_file)
            content_hash = asset_info["content_hash"]

            retrieved_asset = registry.get_asset(content_hash)
            assert retrieved_asset["content_hash"] == content_hash
            assert retrieved_asset["path"] == str(test_file)

    def test_asset_exists_check(self):
        """Test checking if asset exists by hash."""
        with tempfile.TemporaryDirectory() as temp_dir:
            registry_path = Path(temp_dir) / "registry.json"
            test_file = Path(temp_dir) / "asset.txt"
            test_file.write_text("Existence test content")

            registry = AssetRegistry(registry_path)
            asset_info = registry.register_asset(test_file)
            content_hash = asset_info["content_hash"]

            assert registry.asset_exists(content_hash)
            assert not registry.asset_exists("nonexistent_hash")


class TestAssetRegistryPersistence:
    """Test JSON persistence and file operations."""

    def test_registry_persists_to_json(self):
        """Test that registry changes are persisted to JSON file."""
        with tempfile.TemporaryDirectory() as temp_dir:
            registry_path = Path(temp_dir) / "registry.json"
            test_file = Path(temp_dir) / "asset.txt"
            test_file.write_text("Content to persist")

            registry = AssetRegistry(registry_path)
            registry.register_asset(test_file)

            # Verify JSON file contains our asset
            with open(registry_path) as f:
                data = json.load(f)
                assert "assets" in data
                assert len(data["assets"]) == 1

    def test_registry_handles_corrupted_json(self):
        """Test registry handles corrupted JSON gracefully."""
        with tempfile.TemporaryDirectory() as temp_dir:
            registry_path = Path(temp_dir) / "corrupted_registry.json"
            registry_path.write_text("{ invalid json content")

            # Should handle corrupted JSON and create new registry
            registry = AssetRegistry(registry_path)
            assets = registry.list_assets()
            assert assets == []


class TestAssetRegistryThreadSafety:
    """Test thread-safe registry operations."""

    def test_concurrent_asset_registration(self):
        """Test that multiple threads can register assets simultaneously."""
        with tempfile.TemporaryDirectory() as temp_dir:
            registry_path = Path(temp_dir) / "registry.json"
            registry = AssetRegistry(registry_path)

            results = []
            errors = []

            def register_asset_thread(thread_id):
                try:
                    test_file = Path(temp_dir) / f"asset_{thread_id}.txt"
                    test_file.write_text(f"Content for thread {thread_id}")
                    asset_info = registry.register_asset(test_file)
                    results.append(asset_info)
                except Exception as e:
                    errors.append(e)

            # Start multiple threads
            threads = []
            for i in range(5):
                thread = threading.Thread(target=register_asset_thread, args=(i,))
                threads.append(thread)
                thread.start()

            # Wait for all threads to complete
            for thread in threads:
                thread.join()

            assert len(errors) == 0, f"Thread safety errors: {errors}"
            assert len(results) == 5
            assert len(set(r["content_hash"] for r in results)) == 5  # All unique hashes


class TestAssetRegistryErrorHandling:
    """Test error handling and exception scenarios."""

    def test_register_nonexistent_file_raises_error(self):
        """Test that registering non-existent file raises appropriate error."""
        with tempfile.TemporaryDirectory() as temp_dir:
            registry_path = Path(temp_dir) / "registry.json"
            nonexistent_file = Path(temp_dir) / "does_not_exist.txt"

            registry = AssetRegistry(registry_path)

            with pytest.raises(AssetError):
                registry.register_asset(nonexistent_file)

    def test_get_nonexistent_asset_raises_error(self):
        """Test that getting non-existent asset raises appropriate error."""
        with tempfile.TemporaryDirectory() as temp_dir:
            registry_path = Path(temp_dir) / "registry.json"
            registry = AssetRegistry(registry_path)

            with pytest.raises(RegistryError):
                registry.get_asset("nonexistent_hash_12345")

    def test_invalid_registry_path_raises_error(self):
        """Test that invalid registry path raises appropriate error."""
        invalid_path = Path("/root/protected/cannot_write.json")

        with pytest.raises(RegistryError):
            AssetRegistry(invalid_path)