"""Tests for persistence behavior (save on quit/disconnect)."""

import os
import tempfile
from unittest.mock import AsyncMock, MagicMock

import pytest

from mudlib.commands.quit import cmd_quit
from mudlib.player import Player, players
from mudlib.store import create_account, init_db, load_player_data, save_player


@pytest.fixture
def temp_db():
    """Create a temporary database for testing."""
    with tempfile.NamedTemporaryFile(delete=False, suffix=".db") as f:
        db_path = f.name

    init_db(db_path)

    yield db_path

    # Cleanup
    os.unlink(db_path)


@pytest.fixture
def mock_writer():
    writer = MagicMock()
    writer.write = MagicMock()
    writer.drain = AsyncMock()
    writer.close = MagicMock()
    writer.is_closing = MagicMock(return_value=False)
    return writer


@pytest.fixture
def mock_reader():
    return MagicMock()


@pytest.mark.asyncio
async def test_quit_saves_player_state(temp_db, mock_reader, mock_writer):
    """Quit command saves player state before disconnecting."""
    # Create an account
    create_account("TestPlayer", "password")

    # Create player with modified state
    player = Player(
        name="TestPlayer",
        x=42,
        y=17,
        pl=85.0,
        stamina=60.0,
        max_stamina=120.0,
        flying=True,
        reader=mock_reader,
        writer=mock_writer,
    )

    # Add to player registry
    players["TestPlayer"] = player

    # Execute quit command
    await cmd_quit(player, "")

    # Verify player was saved
    data = load_player_data("TestPlayer")
    assert data is not None
    assert data["x"] == 42
    assert data["y"] == 17
    assert data["pl"] == 85.0
    assert data["stamina"] == 60.0
    assert data["max_stamina"] == 120.0
    assert data["flying"] is True

    # Verify player was removed from registry
    assert "TestPlayer" not in players


@pytest.mark.asyncio
async def test_save_multiple_times(temp_db, mock_reader, mock_writer):
    """Player state can be saved multiple times (updates)."""
    create_account("TestPlayer", "password")

    player = Player(
        name="TestPlayer",
        x=10,
        y=20,
        reader=mock_reader,
        writer=mock_writer,
    )

    # Save initial state
    players["TestPlayer"] = player
    await cmd_quit(player, "")

    # Verify initial save
    data = load_player_data("TestPlayer")
    assert data is not None
    assert data["x"] == 10
    assert data["y"] == 20

    # Create new player instance with different position
    player2 = Player(
        name="TestPlayer",
        x=50,
        y=60,
        reader=mock_reader,
        writer=mock_writer,
    )

    # Save again
    players["TestPlayer"] = player2
    await cmd_quit(player2, "")

    # Verify updated state
    data = load_player_data("TestPlayer")
    assert data is not None
    assert data["x"] == 50
    assert data["y"] == 60


@pytest.mark.asyncio
async def test_autosave_persists_player_changes(temp_db, mock_reader, mock_writer):
    """Auto-save persists player state changes during gameplay."""
    create_account("TestPlayer", "password")

    # Create player
    player = Player(
        name="TestPlayer",
        x=10,
        y=20,
        pl=100.0,
        reader=mock_reader,
        writer=mock_writer,
    )

    # Simulate player moving and taking damage
    player.x = 25
    player.y = 35
    player.pl = 75.0

    # Manually trigger save (simulating auto-save)
    save_player(player)

    # Verify state was saved
    data = load_player_data("TestPlayer")
    assert data is not None
    assert data["x"] == 25
    assert data["y"] == 35
    assert data["pl"] == 75.0
