from __future__ import annotations

from pathlib import Path

from app.models import (
    DocumentElement,
    DocumentModel,
    ElementType,
    FontSettings,
    PageState,
    TableData,
)
from app.utils import CoordinateMapper


def test_normalized_coordinates() -> None:
    result = CoordinateMapper.pdf_to_normalized(
        200,
        300,
        400,
        100,
        1000,
        2000,
    )

    assert result == (
        0.2,
        0.15,
        0.4,
        0.05,
    )


def test_normalized_to_pdf() -> None:
    result = CoordinateMapper.normalized_to_pdf(
        0.2,
        0.15,
        0.4,
        0.05,
        1000,
        2000,
    )

    assert result == (
        200,
        300,
        400,
        100,
    )


def test_zoom_does_not_change_normalized_coordinates() -> None:
    original = (
        0.2,
        0.3,
        0.4,
        0.1,
    )

    view = CoordinateMapper.normalized_to_view(
        *original,
        100,
        50,
        1000,
        1500,
    )

    recovered = CoordinateMapper.view_to_normalized(
        *view,
        100,
        50,
        1000,
        1500,
    )

    assert all(
        abs(a - b) < 1e-9
        for a, b in zip(original, recovered)
    )


def test_document_element() -> None:
    element = DocumentElement(
        element_type=ElementType.TEXT,
        x=0.2,
        y=0.3,
        width=0.4,
        height=0.1,
        page_number=1,
        text="Hello",
    )

    assert element.element_type == ElementType.TEXT
    assert element.rect() == (
        0.2,
        0.3,
        0.4,
        0.1,
    )


def test_page_state() -> None:
    page = PageState(
        page_number=2,
        width_pt=612,
        height_pt=792,
    )

    page.elements.append(
        DocumentElement(
            element_type=ElementType.IMAGE,
            x=0.1,
            y=0.2,
            width=0.3,
            height=0.4,
            page_number=2,
        )
    )

    assert len(page.elements) == 1
    assert page.orientation == "portrait"


def test_skipped_pages_remain() -> None:
    model = DocumentModel(
        pages=[
            PageState(
                page_number=1,
                width_pt=612,
                height_pt=792,
                processed=True,
            ),
            PageState(
                page_number=2,
                width_pt=612,
                height_pt=792,
                processed=False,
            ),
            PageState(
                page_number=3,
                width_pt=612,
                height_pt=792,
                processed=True,
            ),
        ]
    )

    assert len(model.pages) == 3
    assert model.pages[1].elements == []
    assert model.pages[1].processed is False


def test_project_save_load(tmp_path: Path) -> None:
    project = tmp_path / "sample.pdfocrproject"

    model = DocumentModel(
        source_pdf="sample.pdf",
        output_docx="sample.docx",
        current_page=2,
        font=FontSettings(
            family="Arial",
            size_pt=14,
            bold=True,
        ),
        pages=[
            PageState(
                page_number=1,
                width_pt=612,
                height_pt=792,
                processed=True,
                elements=[
                    DocumentElement(
                        element_type=ElementType.TEXT,
                        x=0.1,
                        y=0.2,
                        width=0.5,
                        height=0.1,
                        page_number=1,
                        text="Project text",
                    )
                ],
            )
        ],
    )

    model.save_project(project)

    restored = DocumentModel.load_project(project)

    assert restored.source_pdf == "sample.pdf"
    assert restored.current_page == 2
    assert restored.font.family == "Arial"
    assert restored.font.size_pt == 14
    assert restored.pages[0].elements[0].text == "Project text"


def test_table_serialization() -> None:
    table = TableData(
        rows=[
            ["A", "B"],
            ["1", "2"],
        ],
        column_widths=[50, 50],
        row_heights=[20, 20],
    )

    restored = TableData.from_dict(table.to_dict())

    assert restored.rows == table.rows
    assert restored.column_widths == table.column_widths
    assert restored.row_heights == table.row_heights


def test_multiple_elements_same_page() -> None:
    page = PageState(
        page_number=1,
        width_pt=612,
        height_pt=792,
    )

    page.elements.extend(
        [
            DocumentElement(
                element_type=ElementType.TEXT,
                x=0.05,
                y=0.05,
                width=0.4,
                height=0.1,
                page_number=1,
                text="Text",
            ),
            DocumentElement(
                element_type=ElementType.IMAGE,
                x=0.05,
                y=0.2,
                width=0.4,
                height=0.3,
                page_number=1,
            ),
            DocumentElement(
                element_type=ElementType.TABLE,
                x=0.55,
                y=0.2,
                width=0.4,
                height=0.3,
                page_number=1,
            ),
        ]
    )

    assert len(page.elements) == 3