"""Tests for the VaultModule."""

from __future__ import annotations

from unittest.mock import AsyncMock, patch

import pytest
from eth_abi import encode

from openhedge.models.vault import Vault, VaultNav
from tests.conftest import FAKE_TX_HASH, FAKE_VAULT, make_rpc_response


def _encode_rpc(types, values):
    """Helper to ABI-encode and return as 0x-prefixed hex."""
    return "0x" + encode(types, values).hex()


class TestVaultGet:
    async def test_get_vault_state(self, agent):
        # Mock all the eth_call responses for each view function
        responses = [
            make_rpc_response(_encode_rpc(["string"], ["Alpha Vault"])),   # name
            make_rpc_response(_encode_rpc(["string"], ["ohALPHA"])),        # symbol
            make_rpc_response(_encode_rpc(["address"], ["0x" + "aa" * 20])), # asset
            make_rpc_response(_encode_rpc(["address"], ["0x" + "bb" * 20])), # trader
            make_rpc_response(_encode_rpc(["address"], ["0x" + "cc" * 20])), # owner
            make_rpc_response(_encode_rpc(["uint256"], [5000000])),          # totalAssets
            make_rpc_response(_encode_rpc(["uint256"], [5000000])),          # totalSupply
            make_rpc_response(_encode_rpc(["uint256"], [1000000])),          # sharePrice
            make_rpc_response(_encode_rpc(["uint256"], [1000000])),          # highWaterMark
            make_rpc_response(_encode_rpc(["uint8"], [6])),                  # decimals
            make_rpc_response(_encode_rpc(["(uint16,uint16,uint16)"], [(500, 2000, 3000)])),  # guardrails
        ]

        call_count = 0
        async def mock_post(*args, **kwargs):
            nonlocal call_count
            resp = responses[call_count]
            call_count += 1
            return resp

        with patch.object(agent._http, "post", side_effect=mock_post):
            vault = await agent.vault.get(FAKE_VAULT)

        assert isinstance(vault, Vault)
        assert vault.name == "Alpha Vault"
        assert vault.symbol == "ohALPHA"
        assert vault.total_assets == 5000000
        assert vault.guardrails is not None
        assert vault.guardrails.max_leverage_bps == 500


class TestVaultNav:
    async def test_nav_returns_vault_nav(self, agent):
        responses = [
            make_rpc_response(_encode_rpc(["uint256"], [1050000])),  # sharePrice
            make_rpc_response(_encode_rpc(["uint256"], [5000000])),  # totalAssets
            make_rpc_response(_encode_rpc(["uint256"], [5000000])),  # totalSupply
        ]
        call_count = 0

        async def mock_post(*args, **kwargs):
            nonlocal call_count
            resp = responses[min(call_count, len(responses) - 1)]
            call_count += 1
            return resp

        with patch.object(agent._http, "post", side_effect=mock_post):
            nav = await agent.vault.nav(FAKE_VAULT)
            assert isinstance(nav, VaultNav)
            assert nav.share_price == 1050000
            assert nav.total_assets == 5000000
            assert nav.total_supply == 5000000
            assert nav.address == FAKE_VAULT


class TestVaultDeployParsing:
    def test_parse_vault_deployed_event(self):
        """Test event log parsing for VaultDeployed."""
        from openhedge.modules.vault import VaultModule

        vault_addr = "0x" + "dd" * 20
        # topic[2] is the vault address, zero-padded to 32 bytes
        padded = "0x" + "00" * 12 + "dd" * 20
        receipt = {
            "logs": [
                {
                    "topics": [
                        "0x" + "ab" * 32,  # event sig
                        "0x" + "00" * 12 + "bb" * 20,  # trader
                        padded,  # vault
                    ]
                }
            ]
        }
        result = VaultModule._parse_vault_deployed(receipt)
        assert result.lower() == vault_addr.lower()
