import sys
from pathlib import Path
import sqlite3
import tempfile

ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))

from database import Database
from item_catalog import CatalogIdentity, ItemCatalog, VariantSelection
from official_stats import OfficialItemClient
from rules import RuleBook

RULES = RuleBook(ROOT / "data")


def test_catalog_has_all_structural_identities_and_lazy_variants():
    catalog = ItemCatalog(RULES)
    assert catalog.identity_count() == 22517
    assert catalog.variant_count() == 1080816
    assert sum(row["identities"] for row in catalog.statistics()) == 22517


def test_catalog_blank_filters_are_real_filters():
    catalog = ItemCatalog(RULES)
    rows = catalog.filter(category="head", prefix_semantic="__EMPTY__", suffix="__EMPTY__")
    assert len(rows) == 10
    assert all(not row.prefix and not row.suffix for row in rows)


def test_sqlite_export_contains_generated_variant_view():
    catalog = ItemCatalog(RULES)
    with tempfile.TemporaryDirectory() as tmp:
        path = catalog.export_sqlite(Path(tmp) / "catalog.sqlite")
        conn = sqlite3.connect(path)
        try:
            assert conn.execute("SELECT COUNT(*) FROM item_identities").fetchone()[0] == 22517
            assert conn.execute("SELECT COUNT(*) FROM quality_levels").fetchone()[0] == 24
            assert conn.execute("SELECT COUNT(*) FROM all_variants").fetchone()[0] == 1080816
        finally:
            conn.close()


def test_official_stats_parser_extracts_fields():
    html = """
    <html><body>
      <div>Przedmiot: Legendarna Dobra Ostra Pięść Dowódcy (+2)</div>
      <div>Broń biała jednoręczna (PŁEĆ : Dowolna)</div>
      <div>Obrażenia: 7 - 13</div>
      <div>Cechy: trafienie +3, CHARYZMA +3</div>
      <div>Wymagania: POZIOM: 9, SIŁA: 4</div>
      <div>Cena: 1 000 PLN ; Cena sprzedaży: 500 PLN ; Mana: 4 ; Nanity: 2</div>
      <div>STREFA - Przedmiot: 1 , 2</div>
      <div>STREFA - prefix: 1</div>
      <div>STREFA - suffix: 2</div>
      <div>STREFA - PODSUMOWANIE : 1 , 2</div>
      <div>Rzadkość - Przedmiot: 1</div>
      <div>Rzadkość - prefix: 2</div>
      <div>Rzadkość - suffix: 3</div>
      <div>Rzadkość - PODSUMOWANIE : 4</div>
    </body></html>
    """
    selection = VariantSelection(
        CatalogIdentity("melee1h", "ostry", "palka", "dowodcy"),
        quality="Dobry", upgrade=2, legendary=True, player_level=80,
    )
    stats = OfficialItemClient.parse(html, selection, "https://example.invalid")
    assert stats.item_name.startswith("Legendarna")
    assert stats.damage == "7 - 13"
    assert stats.features.startswith("trafienie")
    assert stats.price == "1 000 PLN"
    assert stats.sell_price == "500 PLN"
    assert stats.mana == "4"
    assert stats.nanites == "2"
    assert stats.zone_total == "1 , 2"
    assert stats.rarity_total == "4"


def test_official_client_resolves_links_from_page_structure_without_hardcoded_ids():
    index = """
      <a href='?baseType=14&class=0&legendary=0&playerLvl=80&prefix=0&sufix=0'>Pałka</a>
    """
    base = """
      <a href='?baseType=14&class=0&legendary=0&playerLvl=80&prefix=1&sufix=0'>Ostra</a>
      <a href='?baseType=14&class=0&legendary=0&playerLvl=80&prefix=0&sufix=1'>Dowódcy</a>
    """
    client = OfficialItemClient(RULES)
    client._get = lambda url: index if url.endswith("test_items.php/") else base
    selection = VariantSelection(
        CatalogIdentity("melee1h", "ostry", "palka", "dowodcy"),
        quality="Doskonały", upgrade=4, legendary=True, player_level=91,
    )
    url = client.build_url(selection)
    assert "baseType=14" in url
    assert "prefix=1" in url
    assert "sufix=1" in url
    assert "class=16" in url
    assert "legendary=1" in url
    assert "playerLvl=91" in url


def test_stats_cache_roundtrip():
    html = "<div>Przedmiot: Pałka</div><div>Broń biała jednoręczna (PŁEĆ : Dowolna)</div><div>Obrażenia: 3 - 6</div>"
    selection = VariantSelection(CatalogIdentity("melee1h", "", "palka", ""))
    stats = OfficialItemClient.parse(html, selection, "https://example.invalid")
    with tempfile.TemporaryDirectory() as tmp:
        db = Database(Path(tmp) / "db.sqlite")
        db.upsert_encyclopedia_stats(stats)
        row = db.get_encyclopedia_stats(selection.cache_key())
        assert row is not None
        assert row["item_name"] == "Pałka"
        assert row["damage"] == "3 - 6"
        assert db.encyclopedia_cache_count() == 1
        db.close()


def test_official_stats_parser_handles_real_split_node_layout():
    html = """
    <html><body>
      <div><span>Przedmiot:</span><b>Archaiczny Amulet Koncentracji (+5)</b></div>
      <div><img alt="Image"><img alt="Image"></div>
      <div>Amulet <span>(PŁEĆ : Dowolna)</span></div>
      <div><strong>Cechy:</strong></div><div>WYGLĄD +10, PKT KRWI -16 %</div>
      <div><strong>Wymagania:</strong></div><div>POZIOM: 90, SIŁA: 13</div>
      <div>
        <span>Cena:</span><b>229 000 PLN</b> ;
        <span>Cena sprzedaży:</span><b>114 500 PLN</b> ;
        <span>Mana:</span>1377 ; <span>Nanity:</span>305
      </div>
      <div>STREFA - Przedmiot: 1 , 2 , 3 , 4 , 5</div>
      <div>STREFA - prefix: 1 , 2 , 3 , 4 , 5</div>
      <div>STREFA - suffix: 1 , 2 , 3 , 4 , 5</div>
      <div>STREFA - PODSUMOWANIE : 1 , 2 , 3 , 4 , 5</div>
      <div>Rzadkość - Przedmiot: 2</div>
      <div>Rzadkość - prefix: 4</div>
      <div>Rzadkość - suffix: 5</div>
      <div>Rzadkość - PODSUMOWANIE : 10</div>
    </body></html>
    """
    selection = VariantSelection(
        CatalogIdentity("amulet", "archaiczny", "amulet", "koncentracji"),
        quality="Zwykły", upgrade=5, legendary=False, player_level=80,
    )
    stats = OfficialItemClient.parse(html, selection, "https://example.invalid")
    assert stats.is_valid()
    assert stats.item_name == "Archaiczny Amulet Koncentracji (+5)"
    assert stats.item_category == "Amulet (PŁEĆ : Dowolna)"
    assert stats.features == "WYGLĄD +10, PKT KRWI -16 %"
    assert stats.requirements == "POZIOM: 90, SIŁA: 13"
    assert stats.price == "229 000 PLN"
    assert stats.sell_price == "114 500 PLN"
    assert stats.mana == "1377"
    assert stats.nanites == "305"
    assert stats.zone_total == "1 , 2 , 3 , 4 , 5"
    assert stats.rarity_total == "10"


def test_official_fetch_rejects_unparsed_page_instead_of_caching_success():
    selection = VariantSelection(CatalogIdentity("amulet", "", "amulet", ""))
    client = OfficialItemClient(RULES)
    client.build_url = lambda _selection: "https://example.invalid/result"
    client._get = lambda _url: "<html><body>temporary error page</body></html>"
    try:
        client.fetch(selection)
    except Exception as exc:
        assert "nie udało się odczytać" in str(exc)
    else:
        raise AssertionError("Malformed page should not be treated as valid official stats")


def test_database_removes_old_malformed_encyclopedia_cache_rows():
    with tempfile.TemporaryDirectory() as tmp:
        path = Path(tmp) / "db.sqlite"
        db = Database(path)
        db.conn.execute(
            """INSERT INTO encyclopedia_stats(
                cache_key,url,category,prefix,base,suffix,quality,upgrade,legendary,
                player_level,item_name,item_category,fetched_at
            ) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)""",
            ("bad", "x", "amulet", "", "amulet", "", "Zwykły", 0, 0, 80, "", "Amulet", "now"),
        )
        db.conn.commit()
        db.close()
        reopened = Database(path)
        try:
            assert reopened.get_encyclopedia_stats("bad") is None
            assert reopened.encyclopedia_cache_count() == 0
        finally:
            reopened.close()


def test_official_stats_parser_accepts_heavy_ranged_subtype_before_gender():
    html = """
    <html><body>
      <div><span>Przedmiot:</span><b>Legendarna Dobra Ciężka kusza Dalekiego zasięgu (+5)</b></div>
      <div><img alt="Image"><img alt="Image"></div>
      <div>Broń dystansowa dwuręczna <span>(ciężka)</span> <span>(PŁEĆ : Dowolna)</span></div>
      <div><strong>Obrażenia:</strong> 79 - 139</div>
      <div><strong>Cechy:</strong> trafienie +64, ilość ataków na rundę: 3</div>
      <div><strong>Wymagania:</strong> POZIOM: 76, SIŁA: 88</div>
      <div>Cena: 84 600 PLN ; Cena sprzedaży: 42 300 PLN ; Mana: 4969 ; Nanity: 2289</div>
    </body></html>
    """
    selection = VariantSelection(
        CatalogIdentity("ranged", "", "ciezka kusza", "dalekkiego zasiegu"),
        quality="Dobry", upgrade=5, legendary=True, player_level=80,
    )
    stats = OfficialItemClient.parse(html, selection, "https://example.invalid")
    assert stats.is_valid()
    assert stats.item_name == "Legendarna Dobra Ciężka kusza Dalekiego zasięgu (+5)"
    assert stats.item_category == "Broń dystansowa dwuręczna (ciężka) (PŁEĆ : Dowolna)"
    assert stats.damage == "79 - 139"
    assert stats.features.startswith("trafienie +64")


def test_official_stats_parser_accepts_light_ranged_subtype_before_gender():
    html = """
    <html><body>
      <div>Przedmiot: Epicki Nóż do rzucania Wilka</div>
      <div>Broń dystansowa dwuręczna (lekka) (PŁEĆ: Dowolna)</div>
      <div>Obrażenia: 20 - 40</div>
      <div>Cechy: ilość ataków na rundę: 8</div>
      <div>Wymagania: POZIOM: 50</div>
      <div>Cena: 10 000 PLN</div>
    </body></html>
    """
    selection = VariantSelection(
        CatalogIdentity("ranged", "", "noz do rzucania", "wilka"),
        quality="Epicki", upgrade=0, legendary=False, player_level=80,
    )
    stats = OfficialItemClient.parse(html, selection, "https://example.invalid")
    assert stats.is_valid()
    assert stats.item_name == "Epicki Nóż do rzucania Wilka"
    assert stats.item_category == "Broń dystansowa dwuręczna (lekka) (PŁEĆ: Dowolna)"
    assert stats.damage == "20 - 40"
