"""Tests for quber.core.consolidation module."""

from pathlib import Path
from unittest.mock import Mock, patch

from quber.core.consolidation import HeaderConsolidator, save_metadata
from quber.core.models import TableMetadata


def test_enhanced_table_parser_init_defaults():
    """Test HeaderConsolidator initialization with defaults."""
    parser = HeaderConsolidator()

    assert parser.separator == " ^ "
    assert parser.max_lookback == 10
    assert parser.enable_consolidation is True
    assert parser.debug is False


def test_enhanced_table_parser_init_custom():
    """Test HeaderConsolidator initialization with custom values."""
    parser = HeaderConsolidator(
        separator=" | ",
        max_lookback=5,
        enable_consolidation=False,
        debug=True,
    )

    assert parser.separator == " | "
    assert parser.max_lookback == 5
    assert parser.enable_consolidation is False
    assert parser.debug is True


def test_consolidate_headers_empty():
    """Test consolidating empty headers list."""
    parser = HeaderConsolidator()

    result = parser.consolidate_headers([])

    assert result is None


def test_consolidate_headers_single():
    """Test consolidating single header."""
    parser = HeaderConsolidator()

    result = parser.consolidate_headers(["Header 1"])

    assert result == "Header 1"


def test_consolidate_headers_multiple():
    """Test consolidating multiple headers."""
    parser = HeaderConsolidator()

    result = parser.consolidate_headers(["Header 1", "Header 2", "Header 3"])

    assert result == "Header 1 ^ Header 2 ^ Header 3"


def test_consolidate_headers_custom_separator():
    """Test consolidating headers with custom separator."""
    parser = HeaderConsolidator(separator=" | ")

    result = parser.consolidate_headers(["Part 1", "Part 2"])

    assert result == "Part 1 | Part 2"


def test_get_preceding_text_no_elements():
    """Test getting preceding text with no elements."""
    parser = HeaderConsolidator()
    elements = []

    result = parser.get_preceding_text(elements, 0, limit=3)

    assert result is None


def test_get_preceding_text_single_element():
    """Test getting preceding text with single element."""
    parser = HeaderConsolidator()

    mock_elem = Mock()
    mock_elem.text = "Preceding text content"

    elements = [mock_elem, Mock()]

    result = parser.get_preceding_text(elements, 1, limit=3)

    assert result == "Preceding text content"


def test_get_preceding_text_multiple_elements():
    """Test getting preceding text with multiple elements."""
    parser = HeaderConsolidator()

    elem1 = Mock()
    elem1.text = "First text"

    elem2 = Mock()
    elem2.text = "Second text"

    elem3 = Mock()
    elem3.text = "Third text"

    elements = [elem1, elem2, elem3, Mock()]

    result = parser.get_preceding_text(elements, 3, limit=3)

    assert result == "First text\nSecond text\nThird text"


def test_get_preceding_text_respects_limit():
    """Test that preceding text respects limit parameter."""
    parser = HeaderConsolidator()

    elem1 = Mock()
    elem1.text = "Text 1"

    elem2 = Mock()
    elem2.text = "Text 2"

    elem3 = Mock()
    elem3.text = "Text 3"

    elem4 = Mock()
    elem4.text = "Text 4"

    elements = [elem1, elem2, elem3, elem4, Mock()]

    result = parser.get_preceding_text(elements, 4, limit=2)

    assert result == "Text 3\nText 4"
    assert "Text 1" not in result
    assert "Text 2" not in result


def test_get_preceding_text_skips_empty():
    """Test that preceding text skips empty text elements."""
    parser = HeaderConsolidator()

    elem1 = Mock()
    elem1.text = "Valid text"

    elem2 = Mock()
    elem2.text = "   "

    elem3 = Mock()
    elem3.text = None

    elements = [elem1, elem2, elem3, Mock()]

    result = parser.get_preceding_text(elements, 3, limit=3)

    assert result == "Valid text"


def test_find_preceding_headers_no_headers():
    """Test finding headers when there are no header elements."""
    parser = HeaderConsolidator()

    elem1 = Mock()
    elem1.text = "Regular text"
    delattr(elem1, "level")

    elements = [elem1, Mock()]

    headers, _ = parser.find_preceding_headers(elements, 1)

    assert headers == []


def test_find_preceding_headers_single_header():
    """Test finding single header before table."""
    parser = HeaderConsolidator()

    header = Mock()
    header.text = "Table Header"
    header.level = 1

    elements = [header, Mock()]

    headers, _ = parser.find_preceding_headers(elements, 1)

    assert headers == ["Table Header"]


def test_find_preceding_headers_multiple_same_level():
    """Test finding multiple consecutive headers of same level."""
    parser = HeaderConsolidator()

    header1 = Mock()
    header1.text = "Part 1"
    header1.level = 2

    header2 = Mock()
    header2.text = "Part 2"
    header2.level = 2

    elements = [header1, header2, Mock()]

    headers, _ = parser.find_preceding_headers(elements, 2)

    assert headers == ["Part 1", "Part 2"]


def test_find_preceding_headers_stops_at_different_level():
    """Test that header search stops at different level."""
    parser = HeaderConsolidator()

    header1 = Mock()
    header1.text = "Level 1 Header"
    header1.level = 1

    header2 = Mock()
    header2.text = "Level 2 Header"
    header2.level = 2

    elements = [header1, header2, Mock()]

    headers, _ = parser.find_preceding_headers(elements, 2)

    assert headers == ["Level 2 Header"]
    assert "Level 1 Header" not in headers


def test_find_preceding_headers_stops_at_table():
    """Test that header search stops at table boundary."""
    parser = HeaderConsolidator()

    header = Mock()
    header.text = "Header"
    header.level = 1

    table = Mock()
    table.__class__.__name__ = "TableItem"
    table.text = None

    elements = [table, header, Mock()]

    headers, _ = parser.find_preceding_headers(elements, 2)

    assert headers == ["Header"]


def test_save_metadata(tmp_path: Path):
    """Test saving metadata to JSON file."""
    metadata_list = [
        TableMetadata(
            table_index=0,
            page_number=1,
            headers=["Header 1"],
            consolidated_header="Header 1",
            rows=5,
            cols=3,
        ),
        TableMetadata(
            table_index=1,
            page_number=2,
            headers=["Header 2"],
            consolidated_header="Header 2",
            rows=10,
            cols=4,
        ),
    ]

    output_file = tmp_path / "metadata.json"

    with patch("builtins.print"):
        save_metadata(metadata_list, str(output_file))

    assert output_file.exists()

    import json

    with open(output_file) as f:
        data = json.load(f)

    assert data["total_tables"] == 2
    assert len(data["tables"]) == 2
    assert data["tables"][0]["table_index"] == 0
    assert data["tables"][0]["page_number"] == 1
    assert data["tables"][0]["consolidated_header"] == "Header 1"
    assert data["tables"][1]["table_index"] == 1


def test_print_debug_info():
    """Test debug info printing."""
    parser = HeaderConsolidator(debug=True)

    metadata = TableMetadata(
        table_index=0,
        page_number=1,
        headers=["Header 1", "Header 2"],
        consolidated_header="Header 1 ^ Header 2",
        descriptive_text="This is a test table",
        rows=5,
        cols=3,
        first_cell_content="Cell A1",
    )

    with patch("builtins.print") as mock_print:
        parser.print_debug_info(metadata)

        assert mock_print.called
