"""Tests for the exception hierarchy."""

from __future__ import annotations

import pytest

from openhedge.exceptions import (
    AdapterNotApprovedError,
    AgentNotApprovedError,
    AuthenticationError,
    InsufficientBalanceError,
    InvalidPairError,
    NetworkError,
    NotFoundError,
    OpenHedgeError,
    RateLimitError,
    RiskLimitBreachedError,
    ServerError,
    SlippageExceededError,
    TransactionError,
    ValidationError,
    VaultPausedError,
)


class TestBaseError:
    def test_message_and_attrs(self):
        err = OpenHedgeError("boom", status_code=418, details={"x": 1})
        assert str(err) == "boom"
        assert err.message == "boom"
        assert err.status_code == 418
        assert err.details == {"x": 1}

    def test_defaults(self):
        err = OpenHedgeError("fail")
        assert err.status_code is None
        assert err.details == {}


class TestHttpErrors:
    def test_authentication(self):
        err = AuthenticationError()
        assert err.status_code == 401

    def test_agent_not_approved(self):
        err = AgentNotApprovedError()
        assert err.status_code == 403

    def test_not_found(self):
        err = NotFoundError()
        assert err.status_code == 404

    def test_validation_with_fields(self):
        err = ValidationError(field_errors={"name": "required"})
        assert err.status_code == 422
        assert err.field_errors == {"name": "required"}

    def test_rate_limit(self):
        err = RateLimitError(retry_after=3.5)
        assert err.status_code == 429
        assert err.retry_after == 3.5

    def test_server_error(self):
        err = ServerError()
        assert err.status_code == 500


class TestTransactionErrors:
    def test_transaction_error_with_hash(self):
        err = TransactionError("reverted", tx_hash="0xabc")
        assert err.tx_hash == "0xabc"

    def test_insufficient_balance(self):
        err = InsufficientBalanceError("low balance")
        assert isinstance(err, TransactionError)

    def test_slippage(self):
        err = SlippageExceededError("slippage")
        assert isinstance(err, TransactionError)

    def test_risk_limit(self):
        err = RiskLimitBreachedError("guardrail")
        assert isinstance(err, TransactionError)

    def test_adapter_not_approved(self):
        err = AdapterNotApprovedError("not approved")
        assert isinstance(err, TransactionError)


class TestDomainErrors:
    def test_vault_paused(self):
        err = VaultPausedError()
        assert "paused" in str(err).lower()

    def test_invalid_pair(self):
        err = InvalidPairError("FOO/BAR")
        assert "FOO/BAR" in str(err)

    def test_invalid_pair_empty(self):
        err = InvalidPairError()
        assert "Invalid pair" in str(err)


class TestInheritanceChain:
    def test_all_inherit_from_base(self):
        errors = [
            AuthenticationError(),
            AgentNotApprovedError(),
            NotFoundError(),
            ValidationError(),
            RateLimitError(),
            ServerError(),
            NetworkError(),
            TransactionError("x"),
            InsufficientBalanceError("x"),
            SlippageExceededError("x"),
            RiskLimitBreachedError("x"),
            AdapterNotApprovedError("x"),
            VaultPausedError(),
            InvalidPairError("x"),
        ]
        for err in errors:
            assert isinstance(err, OpenHedgeError)
