"""Tests for Pydantic models."""

from __future__ import annotations

import pytest

from openhedge.models import (
    AgentProfile,
    AgentRegistration,
    Allocation,
    GasEstimate,
    Guardrails,
    LeaderboardEntry,
    PairInfo,
    Portfolio,
    Position,
    TradeQuote,
    TradeResult,
    Vault,
    VaultConfig,
    VaultNav,
    VaultRanking,
)
from openhedge.models.trade import TradeType


class TestAgentModels:
    def test_registration_valid(self):
        reg = AgentRegistration(
            wallet_address="0x" + "aa" * 20,
            name="TestBot",
            strategy_type="momentum",
        )
        assert reg.name == "TestBot"

    def test_registration_name_min(self):
        with pytest.raises(Exception):
            AgentRegistration(wallet_address="0x" + "aa" * 20, name="")

    def test_profile(self):
        p = AgentProfile(
            id="agent_123",
            wallet_address="0x" + "aa" * 20,
            name="TestBot",
            approved=True,
        )
        assert p.approved is True


class TestVaultModels:
    def test_guardrails(self):
        g = Guardrails(max_leverage_bps=500, max_drawdown_bps=2000, max_position_bps=3000)
        assert g.max_leverage_bps == 500

    def test_guardrails_bounds(self):
        with pytest.raises(Exception):
            Guardrails(max_leverage_bps=-1, max_drawdown_bps=0, max_position_bps=0)

    def test_vault_config(self):
        cfg = VaultConfig(
            name="Alpha",
            guardrails=Guardrails(
                max_leverage_bps=500,
                max_drawdown_bps=2000,
                max_position_bps=3000,
            ),
        )
        assert cfg.asset == "USDC"

    def test_vault(self):
        v = Vault(
            address="0x" + "11" * 20,
            name="Alpha",
            symbol="ohALPHA",
            asset="0x" + "22" * 20,
            trader="0x" + "33" * 20,
            owner="0x" + "44" * 20,
            total_assets=1000000,
            total_supply=1000000,
            share_price=1000000,
        )
        assert v.decimals == 6

    def test_vault_nav(self):
        nav = VaultNav(
            address="0x" + "11" * 20,
            share_price=1050000,
            total_assets=5000000,
            total_supply=5000000,
        )
        assert nav.share_price == 1050000
        assert nav.total_assets == 5000000


class TestMarketModels:
    def test_pair_info(self):
        p = PairInfo(name="BTC/USD", pair_index=0)
        assert p.enabled is True

    def test_gas_estimate(self):
        g = GasEstimate(
            gas_limit=300000,
            gas_price_gwei=0.001,
            estimated_cost_eth=0.0000003,
        )
        assert g.estimated_cost_usd is None


class TestTradeModels:
    def test_trade_result(self):
        r = TradeResult(tx_hash="0x" + "ff" * 32, trade_type=TradeType.SWAP)
        assert r.status == 1

    def test_trade_quote(self):
        q = TradeQuote(amount_in=1000, estimated_amount_out=990)
        assert q.price_impact_bps is None

    def test_position(self):
        p = Position(
            trade_index=5,
            vault="0x" + "11" * 20,
            pair_index=0,
            is_long=True,
            collateral=500000,
            leverage=10,
        )
        assert p.is_open is True


class TestPortfolioModels:
    def test_allocation(self):
        a = Allocation(asset="USDC", protocol="spot", amount=1000000)
        assert a.value_usd is None

    def test_portfolio(self):
        p = Portfolio(
            vault="0x" + "11" * 20,
            total_assets=10000000,
            share_price=1000000,
            total_supply=10000000,
        )
        assert p.open_positions_count == 0


class TestLeaderboardModels:
    def test_vault_ranking(self):
        vr = VaultRanking(
            vault_address="0x" + "11" * 20,
            vault_name="Alpha",
            trader="0x" + "33" * 20,
            aum=5000000,
            share_price=1050000,
        )
        assert vr.return_bps == 0

    def test_leaderboard_entry(self):
        le = LeaderboardEntry(
            period="7d",
            vaults=[
                VaultRanking(
                    vault_address="0x" + "11" * 20,
                    vault_name="Alpha",
                    trader="0x" + "33" * 20,
                    aum=5000000,
                    share_price=1050000,
                    rank=1,
                )
            ],
        )
        assert len(le.vaults) == 1
