"""Tests for SessionKeyManager — creation, validation, revocation."""

import pytest
from unittest.mock import MagicMock
from web3 import Web3

from vkp.session import SessionKeyManager, SessionKeyInfo


@pytest.fixture
def manager():
    """Create a SessionKeyManager with mock Web3."""
    w3 = MagicMock(spec=Web3)
    w3.eth = MagicMock()
    return SessionKeyManager(w3, "base-mainnet", "0x1234567890123456789012345678901234567890")


@pytest.fixture
def manager_no_address():
    """Create a SessionKeyManager without contract address."""
    w3 = MagicMock(spec=Web3)
    return SessionKeyManager(w3, "base-mainnet")


def test_create_session_requires_address(manager_no_address):
    """Test session creation fails without manager address."""
    with pytest.raises(ValueError, match="not configured"):
        manager_no_address.create_session(
            from_address="0x1234567890123456789012345678901234567890",
            session_address="0x1234567890123456789012345678901234567890",
        )


def test_create_session_returns_unsigned_tx(manager):
    """Test session creation returns an unsigned transaction."""
    result = manager.create_session(
        from_address="0x1234567890123456789012345678901234567890",
        session_address="0x2345678901234567890123456789012345678901",
        max_value="0.01",
        total_limit="0.1",
        duration_hours=24,
    )
    assert "unsigned_tx" in result
    assert result["description"] == "Create session key"


def test_create_session_with_allowed_contracts(manager):
    """Test session creation with a contract allowlist."""
    result = manager.create_session(
        from_address="0x1234567890123456789012345678901234567890",
        session_address="0x2345678901234567890123456789012345678901",
        max_value="0.05",
        total_limit="0.5",
        duration_hours=12,
        allowed_contracts=["0xABCDEF0123456789012345678901234567890123"],
    )
    assert "unsigned_tx" in result


def test_revoke_session_returns_unsigned_tx(manager):
    """Test revoking a session returns an unsigned transaction."""
    result = manager.revoke_session(
        from_address="0x1234567890123456789012345678901234567890",
        session_id=42,
    )
    assert "unsigned_tx" in result
    assert "42" in result["description"]


def test_revoke_all_returns_unsigned_tx(manager):
    """Test revoking all sessions returns an unsigned transaction."""
    result = manager.revoke_all(
        from_address="0x1234567890123456789012345678901234567890",
    )
    assert "unsigned_tx" in result
    assert "EMERGENCY" in result["description"]


def test_is_valid_requires_address(manager_no_address):
    """Test validity check fails without manager address."""
    with pytest.raises(ValueError, match="not configured"):
        manager_no_address.is_valid(session_id=1)


def test_session_key_info_dataclass():
    """Test SessionKeyInfo dataclass construction."""
    info = SessionKeyInfo(
        session_id=1,
        owner="0xOwner",
        session_address="0xSession",
        max_value_wei=10**16,
        total_limit_wei=10**17,
        total_spent_wei=5 * 10**15,
        remaining_wei=5 * 10**16,
        expires_at=1700000000,
        created_at=1699999000,
        revoked=False,
        allow_any_contract=True,
    )
    assert info.session_id == 1
    assert not info.revoked
    assert info.allow_any_contract
