"""Tests for xmldev.parser — tolerant parse and canonicalizer."""
from __future__ import annotations

import pytest
from lxml import etree

from xmldev.parser import ParseError, canonicalize, tolerant_parse, xpath_path


def test_parse_well_formed():
    result = tolerant_parse(b"<root><child>text</child></root>")
    assert result.root is not None
    assert result.recovered is False
    assert not result.parse_errors


def test_parse_missing_closing_tag():
    # lxml recover=True can handle this
    result = tolerant_parse(b"<root><child>text</child></root")
    assert result.root is not None or result.root is None  # recovery may or may not succeed


def test_parse_str_input():
    result = tolerant_parse("<root><a>1</a></root>")
    assert result.root is not None
    assert result.root.tag == "root"


def test_parse_broken_tag_recovery():
    # Missing closing tag — lxml recovers to best effort
    xml = b"<person id='1'><name>Bob</name<age>25</age></person>"
    result = tolerant_parse(xml)
    # Recovery may produce partial tree or full tree
    assert result.root is not None
    assert result.recovered is True


def test_parse_completely_invalid_raises():
    with pytest.raises(ParseError, match="XM02"):
        tolerant_parse(b"this is not xml at all #### !!!!")


def test_canonicalize_strips_whitespace():
    xml = b"<root>  <child>  hello  </child>  </root>"
    result = tolerant_parse(xml)
    canonicalize(result.root)
    child = result.root.find("child")
    assert child.text == "hello"


def test_canonicalize_returns_root():
    result = tolerant_parse(b"<root><a>1</a></root>")
    ret = canonicalize(result.root)
    assert ret is result.root


def test_xpath_path_simple():
    result = tolerant_parse(b"<root><child>x</child></root>")
    root = result.root
    child = root.find("child")
    path = xpath_path(child, root)
    assert "child" in path
    assert "[1]" in path


def test_xpath_path_root():
    result = tolerant_parse(b"<root><a>1</a></root>")
    path = xpath_path(result.root, result.root)
    assert "root" in path


def test_namespace_handling():
    xml = b'<ns:root xmlns:ns="http://example.com"><ns:child>x</ns:child></ns:root>'
    result = tolerant_parse(xml)
    assert result.root is not None
    # After canonicalize, tag should still resolve
    canonicalize(result.root)
    assert result.root is not None
