"""XML parser tests against hand-built API2 response shapes."""

from __future__ import annotations

import pytest

from bggpipe.models import (
    BGGResponseError,
    parse_collection,
    parse_search,
    parse_things,
)

SEARCH_XML = """<items total="2">
  <item type="boardgame" id="13">
    <name type="primary" value="CATAN"/><yearpublished value="1995"/>
  </item>
  <item type="boardgameexpansion" id="290448">
    <name type="alternate" value="Wingspan: Europa"/>
  </item>
</items>"""

THING_XML = """<items>
  <item type="boardgame" id="266192">
    <name type="primary" sortindex="1" value="Wingspan"/>
    <name type="alternate" sortindex="1" value="Flügelschlag"/>
    <yearpublished value="2019"/>
    <statistics page="1"><ratings>
      <owned value="123456"/>
      <ranks>
        <rank type="subtype" id="1" name="boardgame" value="30"/>
        <rank type="family" id="5497" name="strategygames" value="25"/>
      </ranks>
    </ratings></statistics>
    <versions>
      <item type="boardgameversion" id="465063">
        <name type="primary" value="English edition"/>
        <yearpublished value="2019"/>
        <link type="boardgamepublisher" id="23202" value="Stonemaier Games"/>
        <link type="language" id="2184" value="English"/>
      </item>
      <item type="boardgameversion" id="465064">
        <name type="primary" value="German edition"/>
        <yearpublished value="2019"/>
        <link type="boardgamepublisher" id="22160" value="Feuerland Spiele"/>
        <link type="language" id="2188" value="German"/>
      </item>
    </versions>
  </item>
</items>"""

COLLECTION_XML = """<items totalitems="2">
  <item objecttype="thing" objectid="13" subtype="boardgame" collid="101">
    <name sortindex="1">Catan</name>
    <yearpublished>1995</yearpublished>
    <status own="1" wanttoplay="0"/>
  </item>
  <item objecttype="thing" objectid="266192" subtype="boardgame" collid="102">
    <name sortindex="1">Wingspan</name>
    <status own="0" wishlist="1"/>
    <version><item type="boardgameversion" id="465063"/></version>
  </item>
</items>"""

NOT_RANKED_XML = """<items>
  <item type="boardgame" id="99999">
    <name type="primary" value="Obscurity"/>
    <statistics><ratings>
      <owned value="12"/>
      <ranks><rank type="subtype" id="1" name="boardgame" value="Not Ranked"/></ranks>
    </ratings></statistics>
  </item>
</items>"""

ERROR_XML = (
    "<errors><error><message>Invalid username specified</message></error></errors>"
)


def test_parse_search():
    results = parse_search(SEARCH_XML)
    assert [r.bgg_id for r in results] == [13, 290448]
    assert results[0].name == "CATAN"
    assert results[0].year == 1995
    assert results[1].type == "boardgameexpansion"
    assert results[1].name_type == "alternate"
    assert results[1].year is None


def test_parse_things_with_stats_and_versions():
    (thing,) = parse_things(THING_XML)
    assert thing.name == "Wingspan"  # primary, not alternate
    assert thing.owned == 123456
    assert thing.rank == 30  # boardgame rank, not the family rank
    assert len(thing.versions) == 2
    english = thing.versions[0]
    assert english.version_id == 465063
    assert english.publishers == ("Stonemaier Games",)
    assert english.languages == ("English",)


def test_parse_things_not_ranked_is_none():
    (thing,) = parse_things(NOT_RANKED_XML)
    assert thing.rank is None
    assert thing.owned == 12


def test_parse_collection():
    catan, wingspan = parse_collection(COLLECTION_XML)
    assert (catan.object_id, catan.coll_id, catan.own) == (13, 101, True)
    assert catan.version_id is None
    assert wingspan.own is False  # wishlist item must not count as owned
    assert wingspan.version_id == 465063


def test_error_document_raises():
    with pytest.raises(BGGResponseError, match="Invalid username"):
        parse_collection(ERROR_XML)


def test_search_all_items_malformed_raises():
    xml = '<items total="2"><item type="boardgame"/><item type="boardgame"/></items>'
    with pytest.raises(BGGResponseError):
        parse_search(xml)


def test_search_partial_malformed_tolerated_with_warning():
    xml = (
        '<items total="2">'
        '<item type="boardgame" id="13"><name type="primary" value="CATAN"/></item>'
        '<item type="boardgame"/>'
        "</items>"
    )
    with pytest.warns(UserWarning, match="unparseable"):
        results = parse_search(xml)
    assert [r.bgg_id for r in results] == [13]
