"""
Unit tests for pyPhotoAlbum project module
"""

import pytest
from pyPhotoAlbum.project import Project, Page
from pyPhotoAlbum.page_layout import PageLayout
from pyPhotoAlbum.models import ImageData


class TestPage:
    """Tests for Page class"""

    def test_initialization_default(self):
        """Test Page initialization with default values"""
        layout = PageLayout()
        page = Page(layout=layout, page_number=1)

        assert page.layout is layout
        assert page.page_number == 1

    def test_initialization_with_parameters(self):
        """Test Page initialization with custom parameters"""
        layout = PageLayout()
        page = Page(layout=layout, page_number=5)

        assert page.layout is layout
        assert page.page_number == 5

    def test_page_number_modification(self):
        """Test modifying page number after initialization"""
        layout = PageLayout()
        page = Page(layout=layout, page_number=1)
        page.page_number = 10

        assert page.page_number == 10


class TestProject:
    """Tests for Project class"""

    def test_initialization_default(self):
        """Test Project initialization with default values"""
        project = Project()

        assert project.name == "Untitled Project"
        assert len(project.pages) == 0
        assert project.working_dpi == 300
        assert project.page_size_mm == (140, 140)  # Default 14cm x 14cm square

    def test_print_guide_defaults(self):
        """Test that print guide settings have correct defaults"""
        project = Project()

        assert project.page_bleed_mm == 0.0
        assert project.page_safe_area_mm == 5.0
        assert project.show_print_guides is False

    def test_print_guide_serialization_roundtrip(self):
        """Test that print guide settings are serialized and deserialized correctly"""
        project = Project()
        project.page_bleed_mm = 3.0
        project.page_safe_area_mm = 8.0
        project.show_print_guides = True

        data = project.serialize()

        assert data["page_bleed_mm"] == 3.0
        assert data["page_safe_area_mm"] == 8.0
        assert data["show_print_guides"] is True

        # Deserialize into a new project
        restored = Project()
        restored.deserialize(data)

        assert restored.page_bleed_mm == 3.0
        assert restored.page_safe_area_mm == 8.0
        assert restored.show_print_guides is True

    def test_print_guide_deserialization_defaults(self):
        """Test that missing print guide fields in old data fall back to defaults"""
        project = Project()
        data = project.serialize()

        # Simulate old project file without these keys
        del data["page_bleed_mm"]
        del data["page_safe_area_mm"]
        del data["show_print_guides"]

        restored = Project()
        restored.deserialize(data)

        assert restored.page_bleed_mm == 0.0
        assert restored.page_safe_area_mm == 5.0
        assert restored.show_print_guides is False

    def test_initialization_with_name(self):
        """Test Project initialization with custom name"""
        project = Project(name="My Album")

        assert project.name == "My Album"

    def test_add_page(self):
        """Test adding a page to the project"""
        project = Project()
        layout = PageLayout()
        page = Page(layout=layout, page_number=1)

        project.add_page(page)

        assert len(project.pages) == 1
        assert project.pages[0] is page

    def test_add_multiple_pages(self):
        """Test adding multiple pages to the project"""
        project = Project()

        page1 = Page(layout=PageLayout(), page_number=1)
        page2 = Page(layout=PageLayout(), page_number=2)
        page3 = Page(layout=PageLayout(), page_number=3)

        project.add_page(page1)
        project.add_page(page2)
        project.add_page(page3)

        assert len(project.pages) == 3
        assert project.pages[0] is page1
        assert project.pages[1] is page2
        assert project.pages[2] is page3

    def test_remove_page(self):
        """Test removing a page from the project"""
        project = Project()

        page1 = Page(layout=PageLayout(), page_number=1)
        page2 = Page(layout=PageLayout(), page_number=2)

        project.add_page(page1)
        project.add_page(page2)

        project.remove_page(page1)

        assert len(project.pages) == 1
        assert project.pages[0] is page2

    def test_remove_page_not_in_list(self):
        """Test removing a page that's not in the project"""
        project = Project()
        page1 = Page(layout=PageLayout(), page_number=1)
        page2 = Page(layout=PageLayout(), page_number=2)
        project.add_page(page1)

        # Try to remove a page that was never added
        with pytest.raises(ValueError):
            project.remove_page(page2)

    def test_working_dpi_modification(self):
        """Test modifying working DPI"""
        project = Project()
        project.working_dpi = 300

        assert project.working_dpi == 300

    def test_page_size_modification(self):
        """Test modifying page size"""
        project = Project()
        project.page_size_mm = (300, 400)

        assert project.page_size_mm == (300, 400)

    def test_project_name_modification(self):
        """Test modifying project name"""
        project = Project(name="Initial Name")
        project.name = "New Name"

        assert project.name == "New Name"

    def test_asset_manager_exists(self):
        """Test that project has an asset manager"""
        project = Project()

        assert hasattr(project, "asset_manager")
        assert project.asset_manager is not None

    def test_history_exists(self):
        """Test that project has a history manager"""
        project = Project()

        assert hasattr(project, "history")
        assert project.history is not None

    def test_pages_list_is_mutable(self):
        """Test that pages list can be directly modified"""
        project = Project()
        page = Page(layout=PageLayout(), page_number=1)

        project.pages.append(page)

        assert len(project.pages) == 1
        assert project.pages[0] is page

    def test_empty_project_has_no_pages(self):
        """Test that a new project has no pages"""
        project = Project()

        assert len(project.pages) == 0
        assert project.pages == []


class TestProjectWithPages:
    """Integration tests for Project with Page operations"""

    def test_project_with_populated_pages(self, sample_image_data):
        """Test project with pages containing elements"""
        project = Project(name="Photo Album")

        # Create pages with elements
        for i in range(3):
            layout = PageLayout()
            img = ImageData(image_path=f"image_{i}.jpg", x=10 + i * 10, y=20 + i * 10, width=100, height=100)
            layout.add_element(img)
            page = Page(layout=layout, page_number=i + 1)
            project.add_page(page)

        assert len(project.pages) == 3

        # Check each page has elements
        for i, page in enumerate(project.pages):
            assert len(page.layout.elements) == 1
            assert page.page_number == i + 1

    def test_reorder_pages(self):
        """Test reordering pages in project"""
        project = Project()

        page1 = Page(layout=PageLayout(), page_number=1)
        page2 = Page(layout=PageLayout(), page_number=2)
        page3 = Page(layout=PageLayout(), page_number=3)

        project.add_page(page1)
        project.add_page(page2)
        project.add_page(page3)

        # Swap page 1 and page 3
        project.pages[0], project.pages[2] = project.pages[2], project.pages[0]

        assert project.pages[0] is page3
        assert project.pages[1] is page2
        assert project.pages[2] is page1

    def test_clear_all_pages(self):
        """Test clearing all pages from project"""
        project = Project()

        for i in range(5):
            page = Page(layout=PageLayout(), page_number=i + 1)
            project.add_page(page)

        # Clear all pages
        project.pages.clear()

        assert len(project.pages) == 0

    def test_get_page_by_index(self):
        """Test accessing pages by index"""
        project = Project()

        page1 = Page(layout=PageLayout(), page_number=1)
        page2 = Page(layout=PageLayout(), page_number=2)

        project.add_page(page1)
        project.add_page(page2)

        assert project.pages[0] is page1
        assert project.pages[1] is page2

    def test_insert_page_at_position(self):
        """Test inserting a page at a specific position"""
        project = Project()

        page1 = Page(layout=PageLayout(), page_number=1)
        page2 = Page(layout=PageLayout(), page_number=2)
        page_new = Page(layout=PageLayout(), page_number=99)

        project.add_page(page1)
        project.add_page(page2)

        # Insert new page in the middle
        project.pages.insert(1, page_new)

        assert len(project.pages) == 3
        assert project.pages[0] is page1
        assert project.pages[1] is page_new
        assert project.pages[2] is page2
