import pytest

from app.services.parser_service import ParserService


def test_parse_markdown_returns_standardized_response():
    service = ParserService()
    response = service.parse_markdown("README.md", "# Intro\nBody")

    assert response.parser == "markdown-it-py"
    assert response.sections[0] == ("Intro", 1, "Body")
    assert response.section_metadata[0]["section_title"] == "Intro"
    assert response.section_metadata[0]["section_level"] == 1
    assert response.section_metadata[0]["parent_section"] is None
    assert response.section_metadata[0]["heading_path"] == "Intro"
    assert response.section_segments[0]["section_title"] == "Intro"
    assert response.section_segments[0]["content"] == "Body"
    assert isinstance(response.tokens, list)
    assert isinstance(response.links, list)
    assert isinstance(response.link_entities, list)
    assert isinstance(response.code_blocks, list)
    assert isinstance(response.inline_code, list)
    assert isinstance(response.code_entities, list)
    assert isinstance(response.tables, list)
    assert isinstance(response.table_entities, list)
    assert response.normalized_content == "# Intro\nBody"


def test_parse_markdown_rejects_non_md_files():
    service = ParserService()

    with pytest.raises(ValueError):
        service.parse_markdown("README.txt", "# Intro\nBody")


def test_parse_markdown_extracts_code_entities_with_metadata():
    service = ParserService()
    content = (
        "# API\n"
        "Use `kubectl get pods` to inspect status.\n"
        "```bash\n"
        "if [ \"$ok\" = \"1\" ]; then\n"
        "    echo ready\n"
        "fi\n"
        "```\n"
    )

    response = service.parse_markdown("docs/api.md", content)
    entities = response.code_entities

    assert len(entities) == 2

    inline = entities[0]
    assert inline["entity_type"] == "inline_code"
    assert inline["doc_path"] == "docs/api.md"
    assert inline["section_title"] == "API"
    assert inline["line_number"] == 2
    assert inline["content"] == "kubectl get pods"

    block = entities[1]
    assert block["entity_type"] == "code_block"
    assert block["language"] == "bash"
    assert block["doc_path"] == "docs/api.md"
    assert block["section_title"] == "API"
    assert block["line_number"] == 3
    assert "    echo ready" in block["content"]
    assert block["embedding_text"].startswith("Language: bash\n")
    assert "if [ \"$ok\" = \"1\" ]; then" in block["embedding_text"]


def test_parse_markdown_extracts_table_entities_with_metadata():
    service = ParserService()
    content = (
        "# Endpoints\n"
        "| Method | Path |\n"
        "| --- | --- |\n"
        "| GET | /healthz |\n"
        "| POST | /sync |\n"
    )

    response = service.parse_markdown("docs/api.md", content)

    assert len(response.tables) == 1
    assert len(response.table_entities) == 1

    entity = response.table_entities[0]
    assert entity["entity_type"] == "table"
    assert entity["section_title"] == "Endpoints"
    assert entity["doc_path"] == "docs/api.md"
    assert entity["line_number"] == 2
    assert entity["table_structure"] == {
        "headers": ["Method", "Path"],
        "row_count": 2,
        "column_count": 2,
    }
    assert "Columns: Method | Path" in entity["embedding_text"]
    assert "Row 1: GET | /healthz" in entity["embedding_text"]


def test_parse_markdown_table_entities_handle_malformed_markdown_safely():
    service = ParserService()
    content = "# Broken\n| A | B |\n| - | - |\n| 1 | 2\n"

    response = service.parse_markdown("docs/broken.md", content)

    assert isinstance(response.tables, list)
    assert isinstance(response.table_entities, list)


def test_parse_markdown_table_entities_handle_large_tables():
    service = ParserService()
    rows = "".join(f"| key{i} | value{i} |\n" for i in range(1, 51))
    content = (
        "# Config\n"
        "| Key | Value |\n"
        "| --- | --- |\n"
        f"{rows}"
    )

    response = service.parse_markdown("docs/config.md", content)

    assert len(response.table_entities) == 1
    entity = response.table_entities[0]
    assert entity["table_structure"]["row_count"] == 50
    assert entity["table_structure"]["column_count"] == 2
    assert "Row 50: key50 | value50" in entity["embedding_text"]


def test_parse_markdown_extracts_link_entities_with_metadata_and_normalization():
    service = ParserService()
    content = (
        "# Setup\n"
        "Read [Repo Guide](../README.md), [Local API](./api.md#auth), "
        "[Root Doc](/docs/index.md), [Google](https://google.com), and [Jump](#config).\n"
        "## Config\n"
        "See [Mail](mailto:dev@example.com).\n"
    )

    response = service.parse_markdown("docs/guides/setup.md", content)
    entities = response.link_entities

    assert len(entities) == 6

    assert any(
        item["link_text"] == "Repo Guide"
        and item["link_type"] == "internal"
        and item["link_target"] == "docs/README.md"
        and item["section_title"] == "Setup"
        and item["heading_path"] == "Setup"
        and item["doc_path"] == "docs/guides/setup.md"
        for item in entities
    )
    assert any(
        item["link_text"] == "Local API"
        and item["link_type"] == "internal"
        and item["link_target"] == "docs/guides/api.md#auth"
        for item in entities
    )
    assert any(
        item["link_text"] == "Root Doc"
        and item["link_type"] == "internal"
        and item["link_target"] == "docs/index.md"
        for item in entities
    )
    assert any(
        item["link_text"] == "Google"
        and item["link_type"] == "external"
        and item["link_target"] == "https://google.com"
        for item in entities
    )
    assert any(
        item["link_text"] == "Jump"
        and item["link_type"] == "anchor"
        and item["link_target"] == "#config"
        for item in entities
    )
    assert any(
        item["link_text"] == "Mail"
        and item["link_type"] == "external"
        and item["link_target"] == "mailto:dev@example.com"
        and item["section_title"] == "Config"
        and item["heading_path"] == "Setup / Config"
        for item in entities
    )


def test_parse_markdown_link_entities_handle_malformed_links_safely():
    service = ParserService()
    content = "# Broken\n[missing link(https://example.com\n"

    response = service.parse_markdown("docs/broken.md", content)

    assert isinstance(response.links, list)
    assert isinstance(response.link_entities, list)
