"""
Unit tests for photo rotation serialization/deserialization
Tests that rotated photos render correctly after reload
"""

import pytest
import tempfile
import json
from pathlib import Path
from unittest.mock import MagicMock, patch
from PIL import Image
from pyPhotoAlbum.models import ImageData


class TestRotationSerialization:
    """Tests for rotation serialization and deserialization"""

    @pytest.fixture
    def sample_image(self):
        """Create a sample test image"""
        # Create a 400x200 test image (wider than tall)
        img = Image.new("RGBA", (400, 200), color=(255, 0, 0, 255))
        return img

    def test_serialize_rotation_metadata(self):
        """Test that rotation metadata is serialized correctly"""
        img_data = ImageData(image_path="test.jpg", x=10, y=20, width=100, height=50)
        img_data.pil_rotation_90 = 1  # 90 degree rotation
        img_data.image_dimensions = (400, 200)  # Original dimensions

        # Serialize
        data = img_data.serialize()

        # Verify rotation is saved
        assert data["pil_rotation_90"] == 1
        assert data["image_dimensions"] == (400, 200)
        assert data["rotation"] == 0  # Visual rotation should be 0

    def test_deserialize_rotation_metadata(self):
        """Test that rotation metadata is deserialized correctly"""
        data = {
            "type": "image",
            "position": (10, 20),
            "size": (100, 50),
            "rotation": 0,
            "z_index": 0,
            "image_path": "test.jpg",
            "crop_info": (0, 0, 1, 1),
            "pil_rotation_90": 1,
            "image_dimensions": (400, 200),
        }

        img_data = ImageData()
        img_data.deserialize(data)

        # Verify rotation is loaded
        assert img_data.pil_rotation_90 == 1
        assert img_data.image_dimensions == (400, 200)
        assert img_data.rotation == 0

    def test_image_dimensions_updated_after_rotation(self, sample_image):
        """Test that image_dimensions are updated after rotation is applied"""
        # Create ImageData with original dimensions
        img_data = ImageData(image_path="test.jpg", x=10, y=20, width=100, height=50)
        img_data.pil_rotation_90 = 1  # 90 degree rotation
        img_data.image_dimensions = (400, 200)  # Original dimensions (width=400, height=200)

        # Simulate async image loading with rotation
        # Pass the UNROTATED image - _on_async_image_loaded will apply rotation
        # After 90° rotation, a 400x200 image becomes 200x400
        img_data._on_async_image_loaded(sample_image)

        # Verify dimensions are updated to rotated dimensions
        assert img_data.image_dimensions == (
            200,
            400,
        ), f"Expected rotated dimensions (200, 400), got {img_data.image_dimensions}"
        assert img_data._img_width == 200
        assert img_data._img_height == 400

    def test_image_dimensions_updated_after_180_rotation(self, sample_image):
        """Test that image_dimensions are updated after 180° rotation"""
        img_data = ImageData(image_path="test.jpg", x=10, y=20, width=100, height=50)
        img_data.pil_rotation_90 = 2  # 180 degree rotation
        img_data.image_dimensions = (400, 200)  # Original dimensions

        # Pass the UNROTATED image - _on_async_image_loaded will apply rotation
        # After 180° rotation, dimensions should stay the same
        img_data._on_async_image_loaded(sample_image)

        # Verify dimensions are updated (same as original for 180°)
        assert img_data.image_dimensions == (400, 200)
        assert img_data._img_width == 400
        assert img_data._img_height == 200

    def test_image_dimensions_updated_after_270_rotation(self, sample_image):
        """Test that image_dimensions are updated after 270° rotation"""
        img_data = ImageData(image_path="test.jpg", x=10, y=20, width=100, height=50)
        img_data.pil_rotation_90 = 3  # 270 degree rotation
        img_data.image_dimensions = (400, 200)  # Original dimensions

        # Pass the UNROTATED image - _on_async_image_loaded will apply rotation
        # After 270° rotation, a 400x200 image becomes 200x400
        img_data._on_async_image_loaded(sample_image)

        # Verify dimensions are updated to rotated dimensions
        assert img_data.image_dimensions == (200, 400)
        assert img_data._img_width == 200
        assert img_data._img_height == 400

    def test_serialize_deserialize_roundtrip_with_rotation(self):
        """Test that rotation survives serialize/deserialize roundtrip"""
        # Create ImageData with rotation
        original = ImageData(image_path="test.jpg", x=10, y=20, width=100, height=50)
        original.pil_rotation_90 = 1
        original.image_dimensions = (400, 200)
        original.rotation = 0
        original.z_index = 5

        # Serialize
        data = original.serialize()

        # Deserialize into new object
        restored = ImageData()
        restored.deserialize(data)

        # Verify all fields match
        assert restored.pil_rotation_90 == original.pil_rotation_90
        assert restored.image_dimensions == original.image_dimensions
        assert restored.rotation == original.rotation
        assert restored.position == original.position
        assert restored.size == original.size
        assert restored.z_index == original.z_index
        assert restored.image_path == original.image_path

    def test_backward_compatibility_visual_rotation_conversion(self):
        """Test that old visual rotations are converted to pil_rotation_90"""
        # Old format data with visual rotation
        data = {
            "type": "image",
            "position": (10, 20),
            "size": (100, 50),
            "rotation": 90,  # Old visual rotation
            "z_index": 0,
            "image_path": "test.jpg",
            "crop_info": (0, 0, 1, 1),
            "pil_rotation_90": 0,  # Not set in old format
            "image_dimensions": (400, 200),
        }

        img_data = ImageData()
        img_data.deserialize(data)

        # Should convert to pil_rotation_90
        assert img_data.pil_rotation_90 == 1
        assert img_data.rotation == 0  # Visual rotation reset

    def test_dimensions_not_lost_on_reload(self, sample_image):
        """Integration test: dimensions are preserved through save/load cycle"""
        # Step 1: Create and "rotate" an image
        img1 = ImageData(image_path="test.jpg", x=10, y=20, width=100, height=50)
        img1.pil_rotation_90 = 1
        img1.image_dimensions = (400, 200)

        # Simulate first load and rotation - pass UNROTATED image
        img1._on_async_image_loaded(sample_image)

        # Verify dimensions after rotation
        assert img1.image_dimensions == (200, 400)

        # Step 2: Serialize (like saving the project)
        saved_data = img1.serialize()

        # Step 3: Deserialize (like loading the project)
        img2 = ImageData()
        img2.deserialize(saved_data)

        # Verify rotation metadata is preserved
        assert img2.pil_rotation_90 == 1
        # Note: image_dimensions from save will be the rotated dimensions
        assert img2.image_dimensions == (200, 400)

        # Step 4: Simulate reload (async loading happens again) - pass UNROTATED image
        img2._on_async_image_loaded(sample_image)

        # Verify dimensions are STILL correct after reload
        assert img2.image_dimensions == (200, 400), "Dimensions should remain correct after reload"
        assert img2._img_width == 200
        assert img2._img_height == 400
