"""Tests for inventory persistence."""

import json

import pytest

from mudlib.player import Player
from mudlib.store import (
    create_account,
    init_db,
    load_player_data,
    save_player,
)
from mudlib.thing import Thing
from mudlib.things import ThingTemplate, thing_templates
from mudlib.zone import Zone


@pytest.fixture
def db(tmp_path):
    """Initialize a temporary database."""
    db_path = tmp_path / "test.db"
    init_db(db_path)
    return db_path


@pytest.fixture
def test_zone():
    terrain = [["." for _ in range(10)] for _ in range(10)]
    return Zone(
        name="testzone",
        width=10,
        height=10,
        terrain=terrain,
    )


@pytest.fixture(autouse=True)
def register_templates():
    """Register test templates."""
    thing_templates.clear()
    thing_templates["rock"] = ThingTemplate(
        name="rock",
        description="a rock",
        aliases=["stone"],
    )
    thing_templates["sword"] = ThingTemplate(
        name="sword",
        description="a sword",
    )
    yield
    thing_templates.clear()


# --- save ---


def test_save_player_with_inventory(db, test_zone):
    """save_player persists inventory as JSON list of template names."""
    import sqlite3

    create_account("Alice", "pass123")
    player = Player(
        name="Alice",
        x=5,
        y=5,
        location=test_zone,
    )
    Thing(name="rock", location=player)
    Thing(name="sword", location=player)

    save_player(player)

    # Check raw DB value
    conn = sqlite3.connect(str(db))
    cursor = conn.cursor()
    cursor.execute("SELECT inventory FROM accounts WHERE name = ?", ("Alice",))
    row = cursor.fetchone()
    conn.close()

    assert row is not None
    inventory = json.loads(row[0])
    assert sorted(inventory) == ["rock", "sword"]


def test_save_player_empty_inventory(db, test_zone):
    """save_player stores empty list when no inventory."""
    import sqlite3

    create_account("Bob", "pass123")
    player = Player(
        name="Bob",
        x=5,
        y=5,
        location=test_zone,
    )

    save_player(player)

    conn = sqlite3.connect(str(db))
    cursor = conn.cursor()
    cursor.execute("SELECT inventory FROM accounts WHERE name = ?", ("Bob",))
    row = cursor.fetchone()
    conn.close()

    assert row is not None
    assert json.loads(row[0]) == []


# --- load ---


def test_load_player_data_includes_inventory(db):
    """load_player_data returns inventory list."""
    import sqlite3

    create_account("Alice", "pass123")

    # Manually set inventory in DB
    conn = sqlite3.connect(str(db))
    cursor = conn.cursor()
    cursor.execute(
        "UPDATE accounts SET inventory = ? WHERE name = ?",
        (json.dumps(["rock", "sword"]), "Alice"),
    )
    conn.commit()
    conn.close()

    data = load_player_data("Alice")
    assert data is not None
    assert sorted(data["inventory"]) == ["rock", "sword"]


def test_load_player_data_empty_inventory(db):
    """load_player_data returns empty list for no inventory."""
    create_account("Bob", "pass123")
    data = load_player_data("Bob")
    assert data is not None
    assert data["inventory"] == []


def test_save_load_duplicate_items(db, test_zone):
    """Duplicate items (two rocks) round-trip correctly."""
    create_account("Dupes", "pass123")
    player = Player(
        name="Dupes",
        x=5,
        y=5,
        location=test_zone,
    )
    Thing(name="rock", location=player)
    Thing(name="rock", location=player)

    save_player(player)
    data = load_player_data("Dupes")
    assert data is not None
    assert data["inventory"] == ["rock", "rock"]


def test_load_player_data_migration_no_column(db):
    """Old DB without inventory column returns empty list."""

    create_account("Charlie", "pass123")

    # init_db already ran the migration adding the inventory column,
    # so this just verifies a fresh account gets empty inventory

    data = load_player_data("Charlie")
    assert data is not None
    assert data["inventory"] == []
