"""Tests for login and registration flow."""

import os
import tempfile

import pytest

from mudlib.server import handle_login
from mudlib.store import account_exists, authenticate, init_db


@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.mark.asyncio
async def test_login_existing_account_correct_password(temp_db):
    """Login succeeds with correct password."""
    from mudlib.store import create_account

    create_account("TestUser", "correct_password")

    # Mock I/O
    inputs = ["correct_password"]
    outputs = []

    async def mock_write(msg: str):
        outputs.append(msg)

    async def mock_read():
        if inputs:
            return inputs.pop(0)
        return None

    result = await handle_login("TestUser", mock_read, mock_write)

    assert result["success"] is True
    assert result["player_data"] is not None
    assert result["player_data"]["x"] == 0
    assert result["player_data"]["y"] == 0


@pytest.mark.asyncio
async def test_login_existing_account_wrong_password(temp_db):
    """Login fails with wrong password after max attempts."""
    from mudlib.store import create_account

    create_account("TestUser", "correct_password")

    # Mock I/O - provide wrong password 3 times
    inputs = ["wrong1", "wrong2", "wrong3"]
    outputs = []

    async def mock_write(msg: str):
        outputs.append(msg)

    async def mock_read():
        if inputs:
            return inputs.pop(0)
        return None

    result = await handle_login("TestUser", mock_read, mock_write)

    assert result["success"] is False
    assert "Too many failed attempts" in "".join(outputs)


@pytest.mark.asyncio
async def test_login_existing_account_retry_success(temp_db):
    """Login succeeds after retrying wrong password."""
    from mudlib.store import create_account

    create_account("TestUser", "correct_password")

    # Mock I/O - wrong password first, then correct
    inputs = ["wrong_password", "correct_password"]
    outputs = []

    async def mock_write(msg: str):
        outputs.append(msg)

    async def mock_read():
        if inputs:
            return inputs.pop(0)
        return None

    result = await handle_login("TestUser", mock_read, mock_write)

    assert result["success"] is True
    assert result["player_data"] is not None


@pytest.mark.asyncio
async def test_registration_new_account(temp_db):
    """Registration creates a new account."""
    # Mock I/O - answer 'y' to create account, then provide password twice
    inputs = ["y", "newpassword", "newpassword"]
    outputs = []

    async def mock_write(msg: str):
        outputs.append(msg)

    async def mock_read():
        if inputs:
            return inputs.pop(0)
        return None

    result = await handle_login("NewUser", mock_read, mock_write)

    assert result["success"] is True
    assert account_exists("NewUser")
    assert authenticate("NewUser", "newpassword")


@pytest.mark.asyncio
async def test_registration_password_mismatch(temp_db):
    """Registration fails if passwords don't match."""
    # Mock I/O - answer 'y', then mismatched passwords, then cancel
    inputs = ["y", "password1", "password2", "n"]
    outputs = []

    async def mock_write(msg: str):
        outputs.append(msg)

    async def mock_read():
        if inputs:
            return inputs.pop(0)
        return None

    result = await handle_login("NewUser", mock_read, mock_write)

    assert result["success"] is False
    assert not account_exists("NewUser")


@pytest.mark.asyncio
async def test_registration_declined(temp_db):
    """User declines to create account."""
    # Mock I/O - answer 'n' to create account
    inputs = ["n"]
    outputs = []

    async def mock_write(msg: str):
        outputs.append(msg)

    async def mock_read():
        if inputs:
            return inputs.pop(0)
        return None

    result = await handle_login("NewUser", mock_read, mock_write)

    assert result["success"] is False
    assert not account_exists("NewUser")
