"""Unit tests: exception hierarchy, attributes, and isinstance checks."""

import pytest

from seaart.exceptions import (
    APIError,
    AccountBlockedError,
    AccountNotFoundError,
    AuthError,
    AuthTokenInvalidError,
    InvalidPasswordError,
    InvalidRequestError,
    MissingDataError,
    SeaArtError,
    StreamInterruptedError,
    TaskTimeoutError,
)


# ── Hierarchy ───────────────────────────────────────────────────────────────


class TestExceptionHierarchy:
    def test_all_inherit_from_seaart_error(self) -> None:
        assert issubclass(APIError, SeaArtError)
        assert issubclass(MissingDataError, SeaArtError)
        assert issubclass(TaskTimeoutError, SeaArtError)
        assert issubclass(InvalidRequestError, SeaArtError)
        assert issubclass(StreamInterruptedError, SeaArtError)

    def test_auth_errors_inherit_from_auth_error(self) -> None:
        assert issubclass(AccountNotFoundError, AuthError)
        assert issubclass(InvalidPasswordError, AuthError)
        assert issubclass(AuthTokenInvalidError, AuthError)
        assert issubclass(AccountBlockedError, AuthError)

    def test_auth_error_inherits_from_api_error(self) -> None:
        assert issubclass(AuthError, APIError)

    def test_task_timeout_is_also_timeout_error(self) -> None:
        err = TaskTimeoutError("timed out")
        assert isinstance(err, TimeoutError)

    def test_invalid_request_is_also_value_error(self) -> None:
        err = InvalidRequestError("bad param")
        assert isinstance(err, ValueError)

    def test_missing_data_not_api_error(self) -> None:
        assert not issubclass(MissingDataError, APIError)

    def test_stream_interrupted_not_api_error(self) -> None:
        assert not issubclass(StreamInterruptedError, APIError)


# ── APIError attributes ─────────────────────────────────────────────────────


class TestAPIErrorAttributes:
    def test_basic_attributes(self) -> None:
        err = APIError(500, b"body", code=10200, msg="server error")
        assert err.http_status == 500
        assert err.code == 10200
        assert err.msg == "server error"
        assert err.body == b"body"

    def test_defaults(self) -> None:
        err = APIError(400, b"")
        assert err.code is None
        assert err.msg is None

    def test_str_representation(self) -> None:
        err = APIError(403, b"", code=20004, msg="forbidden")
        assert "403" in str(err)
        assert "20004" in str(err)

    def test_catchable_as_base(self) -> None:
        with pytest.raises(SeaArtError):
            raise AccountNotFoundError(404, b"", code=20001, msg="not found")

    def test_catchable_as_api_error(self) -> None:
        with pytest.raises(APIError):
            raise AccountBlockedError(403, b"", code=80318, msg="blocked")


# ── MissingDataError ────────────────────────────────────────────────────────


class TestMissingDataError:
    def test_message(self) -> None:
        err = MissingDataError("no data")
        assert "no data" in str(err)

    def test_catchable_as_seaart_error(self) -> None:
        with pytest.raises(SeaArtError):
            raise MissingDataError("test")
