"""
Test scenario for Issue #144: Advanced Asset Processing and Optimization

This test covers format optimization, asset transformation, content analysis,
and similarity detection features.

Issue #144: Phase 3 - Advanced Features and Performance
"""

import pytest
from pathlib import Path
from unittest.mock import Mock, patch, MagicMock
import json
from PIL import Image
import io

from markitect.assets import AssetManager
from markitect.assets.optimizer import AssetOptimizer, OptimizationProfile, OptimizationResult
from markitect.assets.optimizer import AssetTransformer as OptimizerTransformer
from markitect.assets.transformer import AssetTransformer, ThumbnailGenerator
from markitect.assets.analyzer import ContentAnalyzer, SimilarityDetector, AssetMetricsCollector
from tests.test_utils import create_test_workspace, get_test_asset_config


class TestAssetOptimizationAndProcessing:
    """Test advanced asset processing and optimization for Issue #144."""

    def setup_method(self):
        """Set up test environment with sample assets."""
        self.temp_dir = create_test_workspace("asset_optimization")
        self.assets_dir = self.temp_dir / "assets"
        self.test_files_dir = self.temp_dir / "test_files"

        self.assets_dir.mkdir()
        self.test_files_dir.mkdir()

        # Create sample image data
        self.create_test_images()
        self.create_test_documents()

        # Use test asset configuration to ensure isolated registry
        config = get_test_asset_config(self.temp_dir)
        self.asset_manager = AssetManager(config)

    def teardown_method(self):
        """Clean up temporary directories."""
        import shutil
        shutil.rmtree(self.temp_dir, ignore_errors=True)

    def create_test_images(self):
        """Create test images with various properties."""
        # Large PNG image
        large_image = Image.new('RGB', (2000, 1500), color='red')
        large_png_path = self.test_files_dir / "large_image.png"
        large_image.save(large_png_path, 'PNG')

        # High quality JPEG
        high_quality_image = Image.new('RGB', (1200, 800), color='blue')
        high_jpeg_path = self.test_files_dir / "high_quality.jpg"
        high_quality_image.save(high_jpeg_path, 'JPEG', quality=95)

        # SVG content
        svg_content = '''
        <svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
            <circle cx="50" cy="50" r="40" fill="green" />
            <!-- This is a comment that could be removed -->
            <rect x="10" y="10" width="20" height="20" fill="yellow" />
        </svg>
        '''
        svg_path = self.test_files_dir / "diagram.svg"
        svg_path.write_text(svg_content)

    def create_test_documents(self):
        """Create test document files."""
        # Simple PDF placeholder (would be real PDF in production)
        pdf_path = self.test_files_dir / "document.pdf"
        pdf_path.write_bytes(b"%PDF-1.4 mock pdf content")

        # Text document
        text_path = self.test_files_dir / "document.txt"
        text_path.write_text("This is a sample text document with content.")

    def test_asset_optimizer_initialization(self):
        """Test AssetOptimizer initialization with different profiles."""
        # Default profile
        optimizer = AssetOptimizer()
        assert optimizer.profile == OptimizationProfile.BALANCED

        # Custom profile
        custom_profile = OptimizationProfile.AGGRESSIVE
        optimizer_aggressive = AssetOptimizer(profile=custom_profile)
        assert optimizer_aggressive.profile == OptimizationProfile.AGGRESSIVE

    def test_image_compression_optimization(self):
        """Test automatic image compression and format conversion."""
        optimizer = AssetOptimizer(profile=OptimizationProfile.AGGRESSIVE)

        # Test PNG optimization
        png_path = self.test_files_dir / "large_image.png"
        result = optimizer.optimize_image(png_path)

        assert isinstance(result, OptimizationResult)
        assert result.original_size > result.optimized_size
        assert result.size_reduction_percent > 0
        assert result.optimization_type == "image_compression"

        # Verify optimized file exists and is smaller
        assert result.optimized_path.exists()
        assert result.optimized_path.stat().st_size < png_path.stat().st_size

    def test_jpeg_quality_optimization(self):
        """Test JPEG quality optimization with configurable settings."""
        optimizer = AssetOptimizer()

        jpeg_path = self.test_files_dir / "high_quality.jpg"
        result = optimizer.optimize_image(
            jpeg_path,
            target_quality=85,
            max_width=1000
        )

        assert result.original_size > result.optimized_size
        assert result.quality_maintained >= 85

        # Verify image dimensions were reduced if needed
        with Image.open(result.optimized_path) as img:
            assert img.width <= 1000

    def test_svg_optimization_and_minification(self):
        """Test SVG optimization and minification."""
        optimizer = AssetOptimizer()

        svg_path = self.test_files_dir / "diagram.svg"
        result = optimizer.optimize_svg(svg_path)

        assert result.original_size > result.optimized_size

        # Verify comments and whitespace were removed
        optimized_content = result.optimized_path.read_text()
        assert "<!-- This is a comment" not in optimized_content
        assert len(optimized_content) < svg_path.read_text().__len__()

    def test_pdf_compression(self):
        """Test PDF compression for document assets."""
        optimizer = AssetOptimizer()

        pdf_path = self.test_files_dir / "document.pdf"
        result = optimizer.optimize_pdf(pdf_path)

        # For mock PDF, optimization might not reduce size significantly
        assert isinstance(result, OptimizationResult)
        assert result.optimization_type == "pdf_compression"

    def test_thumbnail_generation(self):
        """Test thumbnail generation for images."""
        transformer = OptimizerTransformer()

        image_path = self.test_files_dir / "large_image.png"
        thumbnail_result = transformer.generate_thumbnail(
            image_path,
            size=(150, 150),
            quality=80
        )

        assert thumbnail_result.thumbnail_path.exists()

        # For mock implementation, just verify file was created
        assert thumbnail_result.size == (150, 150)
        assert thumbnail_result.quality == 80

        # Verify thumbnail is smaller than original
        original_size = image_path.stat().st_size
        thumbnail_size = thumbnail_result.file_size
        assert thumbnail_size < original_size

    def test_multi_resolution_variants(self):
        """Test generation of multi-resolution asset variants."""
        transformer = OptimizerTransformer()

        image_path = self.test_files_dir / "large_image.png"
        variants = transformer.generate_resolution_variants(
            image_path,
            resolutions=[(800, 600), (400, 300), (200, 150)]
        )

        assert len(variants) == 3

        for variant in variants:
            assert variant.variant_path.exists()
            assert variant.resolution in [(800, 600), (400, 300), (200, 150)]

    def test_watermarking_functionality(self):
        """Test watermarking and metadata embedding."""
        transformer = OptimizerTransformer()

        image_path = self.test_files_dir / "large_image.png"
        watermarked = transformer.add_watermark(
            image_path,
            watermark_text="© Test Project",
            position="bottom_right",
            opacity=0.7
        )

        assert watermarked.watermarked_path.exists()

        # Verify watermark properties
        assert watermarked.watermark_text == "© Test Project"
        assert watermarked.position == "bottom_right"
        assert watermarked.opacity == 0.7

    def test_content_analysis_image_properties(self):
        """Test image dimension and color profile analysis."""
        analyzer = ContentAnalyzer()

        image_path = self.test_files_dir / "large_image.png"
        analysis = analyzer.analyze_image(image_path)

        assert analysis.width == 2000
        assert analysis.height == 1500
        assert analysis.format == "PNG"
        assert analysis.mode in ["RGB", "RGBA"]
        assert analysis.has_transparency is not None

        # Test color profile analysis
        assert hasattr(analysis, 'dominant_colors')
        assert hasattr(analysis, 'color_histogram')

    def test_document_content_extraction(self):
        """Test document content extraction and indexing."""
        analyzer = ContentAnalyzer()

        text_path = self.test_files_dir / "document.txt"
        analysis = analyzer.analyze_document(text_path)

        assert "sample text document" in analysis.extracted_text.lower()
        assert analysis.word_count > 0
        assert analysis.character_count > 0
        assert len(analysis.keywords) > 0

        # Test language detection
        assert hasattr(analysis, 'detected_language')

    def test_similarity_detection_exact_duplicates(self):
        """Test similarity detection for exact duplicate assets."""
        detector = SimilarityDetector()

        # Create identical files
        file1 = self.test_files_dir / "duplicate1.txt"
        file2 = self.test_files_dir / "duplicate2.txt"

        content = "This is identical content"
        file1.write_text(content)
        file2.write_text(content)

        similarity = detector.calculate_similarity(file1, file2)

        assert similarity.similarity_score == 1.0
        assert similarity.is_exact_duplicate is True
        assert similarity.similarity_type.value == "exact_match"

    def test_similarity_detection_near_duplicates(self):
        """Test similarity detection for near-duplicate images."""
        detector = SimilarityDetector()

        # Create similar images (slightly different)
        image1 = Image.new('RGB', (100, 100), color='red')
        image2 = Image.new('RGB', (100, 100), color=(255, 10, 10))  # Slightly different red

        path1 = self.test_files_dir / "similar1.png"
        path2 = self.test_files_dir / "similar2.png"

        image1.save(path1)
        image2.save(path2)

        similarity = detector.calculate_image_similarity(path1, path2)

        assert similarity.similarity_score > 0.9  # Very similar
        assert similarity.similarity_score < 1.0  # Not identical
        assert similarity.similarity_type.value == "near_duplicate"

    def test_content_based_categorization(self):
        """Test content-based asset categorization."""
        analyzer = ContentAnalyzer()

        # Test image categorization
        image_path = self.test_files_dir / "large_image.png"
        category = analyzer.categorize_asset(image_path)

        assert category.primary_category == "image"
        assert category.sub_category in ["photograph", "graphic", "diagram"]
        assert category.confidence > 0.5

        # Test document categorization
        text_path = self.test_files_dir / "document.txt"
        category = analyzer.categorize_asset(text_path)

        assert category.primary_category == "document"
        assert category.sub_category in ["text", "article", "note"]

    def test_batch_optimization_workflow(self):
        """Test batch optimization workflow for multiple assets."""
        optimizer = AssetOptimizer(profile=OptimizationProfile.BALANCED)

        # Add only supported files to batch (skip text files)
        batch_files = list(self.test_files_dir.glob("*"))
        supported_files = [f for f in batch_files if f.suffix.lower() in ['.png', '.jpg', '.jpeg', '.svg', '.pdf']]

        results = optimizer.optimize_batch(
            supported_files,
            max_concurrent=2,
            progress_callback=Mock()
        )

        assert len(results) == len(supported_files)

        # Verify each result
        for result in results:
            assert isinstance(result, OptimizationResult)
            if result.success:
                assert result.optimized_path.exists()

        # Calculate total savings
        total_original = sum(r.original_size for r in results if r.success)
        total_optimized = sum(r.optimized_size for r in results if r.success)
        total_savings = total_original - total_optimized

        assert total_savings >= 0  # Should never increase size significantly

    def test_configurable_optimization_profiles(self):
        """Test different optimization profiles with varying aggressiveness."""
        conservative = AssetOptimizer(profile=OptimizationProfile.CONSERVATIVE)
        balanced = AssetOptimizer(profile=OptimizationProfile.BALANCED)
        aggressive = AssetOptimizer(profile=OptimizationProfile.AGGRESSIVE)

        image_path = self.test_files_dir / "high_quality.jpg"

        # Test different profiles produce different results
        result_conservative = conservative.optimize_image(image_path)
        result_balanced = balanced.optimize_image(image_path)
        result_aggressive = aggressive.optimize_image(image_path)

        # Aggressive should save more space than conservative
        assert result_aggressive.size_reduction_percent >= result_conservative.size_reduction_percent

        # Quality should be preserved better in conservative mode
        assert result_conservative.quality_maintained >= result_aggressive.quality_maintained

    def test_asset_metrics_collection(self):
        """Test comprehensive asset metrics collection."""
        metrics_collector = AssetMetricsCollector()

        # Analyze all test assets
        for asset_path in self.test_files_dir.glob("*"):
            metrics = metrics_collector.collect_metrics(asset_path)

            assert hasattr(metrics, 'file_size')
            assert hasattr(metrics, 'creation_time')
            assert hasattr(metrics, 'mime_type')
            assert hasattr(metrics, 'optimization_potential')

            if asset_path.suffix.lower() in ['.png', '.jpg', '.jpeg']:
                assert hasattr(metrics, 'image_properties')
                assert metrics.image_properties.width > 0
                assert metrics.image_properties.height > 0

        # Test aggregated metrics
        summary = metrics_collector.get_summary()
        assert summary.total_assets > 0
        assert summary.total_size > 0
        assert summary.optimization_potential_percent >= 0