#!/usr/bin/env python3
"""
Test Media Download Functionality

This script tests that media files (images and attachments) are properly downloaded
to the assets subfolder and referenced correctly in the HTML output.
"""

import asyncio
import json
import logging
import sys
import tempfile
from pathlib import Path
import os
from unittest.mock import AsyncMock, MagicMock

# Add the current directory to the path so we can import modules
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from snapshot_downloader import SnapshotDownloader


class MediaDownloadTester:
    """Test class for media download functionality."""

    def __init__(self):
        """Initialize the tester."""
        self.logger = logging.getLogger(__name__)

    def test_assets_folder_creation(self):
        """Test that assets subfolder is created correctly."""
        print("=" * 60)
        print("TEST: Assets Folder Creation")
        print("=" * 60)

        with tempfile.TemporaryDirectory() as temp_dir:
            print("1. Testing assets folder creation...")

            downloader = SnapshotDownloader(output_dir=temp_dir)

            # Check if assets folder was created
            assets_dir = Path(temp_dir) / "assets"
            if assets_dir.exists() and assets_dir.is_dir():
                print("   ✅ Assets folder created successfully")
            else:
                print("   ❌ Assets folder not created")
                return False

            # Check if it's accessible
            if downloader.assets_dir == assets_dir:
                print("   ✅ Assets directory property set correctly")
            else:
                print("   ❌ Assets directory property incorrect")
                return False

        print("\n✅ Assets folder creation test passed!")
        return True

    def test_filename_sanitization(self):
        """Test filename sanitization functionality."""
        print("\n" + "=" * 60)
        print("TEST: Filename Sanitization")
        print("=" * 60)

        with tempfile.TemporaryDirectory() as temp_dir:
            downloader = SnapshotDownloader(output_dir=temp_dir)

            test_cases = [
                {
                    "input": "normal_filename.jpg",
                    "expected": "normal_filename.jpg",
                    "description": "Normal filename"
                },
                {
                    "input": "file<with>invalid:chars.png",
                    "expected": "file_with_invalid_chars.png",
                    "description": "Invalid characters"
                },
                {
                    "input": "  .leading_trailing_spaces.  ",
                    "expected": "leading_trailing_spaces",
                    "description": "Leading/trailing spaces and dots"
                },
                {
                    "input": "",
                    "expected": "media_file",
                    "description": "Empty filename"
                },
                {
                    "input": "file/with\\path|chars?.txt",
                    "expected": "file_with_path_chars_.txt",
                    "description": "Path characters"
                }
            ]

            print("1. Testing filename sanitization cases...")
            for i, test_case in enumerate(test_cases, 1):
                print(f"\n{i}. {test_case['description']}")
                print(f"   Input: '{test_case['input']}'")

                result = downloader._sanitize_filename(test_case['input'])
                print(f"   Output: '{result}'")

                if result == test_case['expected']:
                    print("   ✅ Correctly sanitized")
                else:
                    print(f"   ❌ Expected: '{test_case['expected']}'")
                    return False

        print("\n✅ Filename sanitization test passed!")
        return True

    async def test_media_download_mock(self):
        """Test media download with mocked HTTP responses."""
        print("\n" + "=" * 60)
        print("TEST: Media Download (Mocked)")
        print("=" * 60)

        with tempfile.TemporaryDirectory() as temp_dir:
            downloader = SnapshotDownloader(output_dir=temp_dir)

            print("1. Testing image download...")

            # Mock media object
            mock_media = {
                "id": 794684,
                "fileName": "test_image.jpeg",
                "type": "image",
                "mimeType": "image/jpeg",
                "updated": "2025-07-31T12:46:24.413",
                "status": "available",
                "downloadable": True
            }

            # Create mock session and response
            mock_response = AsyncMock()
            mock_response.status = 200
            mock_response.raise_for_status = MagicMock()

            # Mock file content
            fake_image_content = b"fake_image_data_for_testing"

            async def mock_iter_chunked(chunk_size):
                yield fake_image_content

            mock_response.content.iter_chunked = mock_iter_chunked

            mock_session = AsyncMock()
            mock_session.get.return_value.__aenter__.return_value = mock_response

            # Test the download
            result = await downloader.download_media_file(mock_session, mock_media)

            # Check result
            if result == "assets/test_image.jpeg":
                print("   ✅ Download returned correct relative path")
            else:
                print(f"   ❌ Expected 'assets/test_image.jpeg', got '{result}'")
                return False

            # Check file was created
            expected_file = Path(temp_dir) / "assets" / "test_image.jpeg"
            if expected_file.exists():
                print("   ✅ File created in assets folder")

                # Check file content
                with open(expected_file, 'rb') as f:
                    content = f.read()
                if content == fake_image_content:
                    print("   ✅ File content matches")
                else:
                    print("   ❌ File content doesn't match")
                    return False
            else:
                print("   ❌ File not created")
                return False

            print("\n2. Testing existing file handling...")

            # Test downloading the same file again (should return existing)
            result2 = await downloader.download_media_file(mock_session, mock_media)
            if result2 == "assets/test_image.jpeg":
                print("   ✅ Existing file handling works")
            else:
                print("   ❌ Existing file handling failed")
                return False

            print("\n3. Testing download failure...")

            # Test with invalid media (no ID)
            invalid_media = {"fileName": "no_id_file.jpg"}
            result3 = await downloader.download_media_file(mock_session, invalid_media)
            if result3 is None:
                print("   ✅ Properly handles invalid media")
            else:
                print("   ❌ Should return None for invalid media")
                return False

        print("\n✅ Media download mock test passed!")
        return True

    async def test_media_formatting_integration(self):
        """Test media formatting with downloaded files."""
        print("\n" + "=" * 60)
        print("TEST: Media Formatting Integration")
        print("=" * 60)

        with tempfile.TemporaryDirectory() as temp_dir:
            downloader = SnapshotDownloader(output_dir=temp_dir)

            print("1. Testing snapshot with media formatting...")

            # Create a test image file in assets
            test_image_path = Path(temp_dir) / "assets" / "test_snapshot_image.jpeg"
            test_image_path.parent.mkdir(exist_ok=True)
            test_image_path.write_bytes(b"fake_image_content")

            # Mock snapshot with media
            mock_snapshot = {
                "id": 123456,
                "type": "Snapshot",
                "child": {"forename": "Test", "surname": "Child"},
                "author": {"forename": "Test", "surname": "Teacher"},
                "startTime": "2024-01-15T10:30:00",
                "notes": "<p>Test snapshot with media</p>",
                "media": [
                    {
                        "id": 123456,
                        "fileName": "test_snapshot_image.jpeg",
                        "type": "image",
                        "mimeType": "image/jpeg",
                        "updated": "2024-01-15T10:30:00",
                        "status": "available",
                        "downloadable": True
                    }
                ]
            }

            # Mock session to simulate successful download
            mock_session = AsyncMock()

            # Override the download_media_file method to return our test path
            original_download = downloader.download_media_file
            async def mock_download(session, media):
                if media.get('fileName') == 'test_snapshot_image.jpeg':
                    return "assets/test_snapshot_image.jpeg"
                return await original_download(session, media)

            downloader.download_media_file = mock_download

            # Test formatting
            html_content = await downloader.format_snapshot_html(mock_snapshot, mock_session)

            print("2. Checking HTML content for media references...")

            # Check for local image reference
            if 'src="assets/test_snapshot_image.jpeg"' in html_content:
                print("   ✅ Local image path found in HTML")
            else:
                print("   ❌ Local image path not found")
                print("   Debug: Looking for image references...")
                if 'assets/' in html_content:
                    print("   Found assets/ references in HTML")
                if 'test_snapshot_image.jpeg' in html_content:
                    print("   Found filename in HTML")
                return False

            # Check for image grid structure
            if 'class="image-grid"' in html_content:
                print("   ✅ Image grid structure present")
            else:
                print("   ❌ Image grid structure missing")
                return False

            # Check for image metadata
            if 'class="image-caption"' in html_content and 'class="image-meta"' in html_content:
                print("   ✅ Image caption and metadata present")
            else:
                print("   ❌ Image caption or metadata missing")
                return False

        print("\n✅ Media formatting integration test passed!")
        return True

    async def test_complete_html_generation_with_media(self):
        """Test complete HTML generation with media downloads."""
        print("\n" + "=" * 60)
        print("TEST: Complete HTML Generation with Media")
        print("=" * 60)

        with tempfile.TemporaryDirectory() as temp_dir:
            downloader = SnapshotDownloader(output_dir=temp_dir)

            print("1. Setting up test environment...")

            # Create test image files
            test_images = ["image1.jpg", "image2.png"]
            for img_name in test_images:
                img_path = Path(temp_dir) / "assets" / img_name
                img_path.write_bytes(f"fake_content_for_{img_name}".encode())

            # Mock snapshots with media
            mock_snapshots = [
                {
                    "id": 100001,
                    "type": "Snapshot",
                    "child": {"forename": "Alice", "surname": "Smith"},
                    "author": {"forename": "Teacher", "surname": "One"},
                    "startTime": "2024-01-15T10:30:00",
                    "notes": "<p>Alice's first snapshot</p>",
                    "media": [
                        {
                            "id": 1001,
                            "fileName": "image1.jpg",
                            "type": "image",
                            "mimeType": "image/jpeg"
                        }
                    ]
                },
                {
                    "id": 100002,
                    "type": "Snapshot",
                    "child": {"forename": "Bob", "surname": "Johnson"},
                    "author": {"forename": "Teacher", "surname": "Two"},
                    "startTime": "2024-01-16T14:20:00",
                    "notes": "<p>Bob's creative work</p>",
                    "media": [
                        {
                            "id": 1002,
                            "fileName": "image2.png",
                            "type": "image",
                            "mimeType": "image/png"
                        }
                    ]
                }
            ]

            # Mock the download_media_file method
            async def mock_download_media(session, media):
                filename = media.get('fileName', 'unknown.jpg')
                if filename in test_images:
                    return f"assets/{filename}"
                return None

            downloader.download_media_file = mock_download_media

            print("2. Generating complete HTML file...")
            html_file = await downloader.generate_html_file(mock_snapshots, "2024-01-01", "2024-12-31")

            if html_file and html_file.exists():
                print("   ✅ HTML file generated successfully")

                with open(html_file, 'r', encoding='utf-8') as f:
                    content = f.read()

                print("3. Checking HTML content...")

                # Check for local image references
                checks = [
                    ('src="assets/image1.jpg"', "Image 1 local reference"),
                    ('src="assets/image2.png"', "Image 2 local reference"),
                    ('Alice by Teacher One', "Snapshot 1 title"),
                    ('Bob by Teacher Two', "Snapshot 2 title"),
                    ('class="image-grid"', "Image grid structure"),
                ]

                all_passed = True
                for check_text, description in checks:
                    if check_text in content:
                        print(f"   ✅ {description} found")
                    else:
                        print(f"   ❌ {description} missing")
                        all_passed = False

                if not all_passed:
                    return False

            else:
                print("   ❌ HTML file not generated")
                return False

        print("\n✅ Complete HTML generation with media test passed!")
        return True

    async def run_all_tests(self):
        """Run all media download tests."""
        print("🚀 Starting Media Download Tests")
        print("=" * 80)

        try:
            success = True

            success &= self.test_assets_folder_creation()
            success &= self.test_filename_sanitization()
            success &= await self.test_media_download_mock()
            success &= await self.test_media_formatting_integration()
            success &= await self.test_complete_html_generation_with_media()

            if success:
                print("\n" + "=" * 80)
                print("🎉 ALL MEDIA DOWNLOAD TESTS PASSED!")
                print("=" * 80)
                print("✅ Assets folder created correctly")
                print("✅ Filename sanitization works properly")
                print("✅ Media files download to assets subfolder")
                print("✅ HTML references local files correctly")
                print("✅ Complete integration working")
                print("\n📁 Media Download Features:")
                print("• Downloads images to assets/ subfolder")
                print("• Downloads attachments to assets/ subfolder")
                print("• Uses relative paths in HTML (assets/filename.jpg)")
                print("• Fallback to API URLs if download fails")
                print("• Sanitizes filenames for filesystem safety")
                print("• Handles existing files (no re-download)")
            else:
                print("\n❌ SOME MEDIA DOWNLOAD TESTS FAILED")

            return success

        except Exception as e:
            print(f"\n❌ MEDIA DOWNLOAD TESTS FAILED: {e}")
            import traceback
            traceback.print_exc()
            return False


def show_media_download_info():
    """Show information about media download functionality."""
    print("\n" + "=" * 80)
    print("📁 MEDIA DOWNLOAD FUNCTIONALITY")
    print("=" * 80)

    print("\n🎯 How It Works:")
    print("1. Creates 'assets' subfolder in output directory")
    print("2. Downloads media files (images, attachments) from API")
    print("3. Saves files with sanitized filenames")
    print("4. Updates HTML to reference local files")
    print("5. Fallback to API URLs if download fails")

    print("\n📋 Supported Media Types:")
    print("• Images: JPEG, PNG, GIF, WebP, etc.")
    print("• Documents: PDF, DOC, TXT, etc.")
    print("• Any file type from ParentZone media API")

    print("\n💾 File Organization:")
    print("output_directory/")
    print("├── snapshots_DATE_to_DATE.html")
    print("├── snapshots.log")
    print("└── assets/")
    print("    ├── image1.jpeg")
    print("    ├── document.pdf")
    print("    └── attachment.txt")

    print("\n🔗 HTML Integration:")
    print("• Images: <img src=\"assets/filename.jpg\">")
    print("• Attachments: <a href=\"assets/filename.pdf\">")
    print("• Relative paths for portability")
    print("• Self-contained reports (HTML + assets)")

    print("\n✨ Benefits:")
    print("• Offline viewing - images work without internet")
    print("• Faster loading - no API requests for media")
    print("• Portable reports - can be shared easily")
    print("• Professional presentation with embedded media")

    print("\n⚠️ Considerations:")
    print("• Requires storage space for downloaded media")
    print("• Download time increases with media count")
    print("• Large files may take longer to process")
    print("• API authentication required for media download")


def main():
    """Main test function."""
    # Setup logging
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    )

    tester = MediaDownloadTester()

    # Run tests
    success = asyncio.run(tester.run_all_tests())

    # Show information
    if success:
        show_media_download_info()

    return 0 if success else 1


if __name__ == "__main__":
    exit(main())
